Merge pull request 'Various Fixes and Changes' (#21) from hotfix-1 into main
All checks were successful
Run Tests on Code / run-tests (push) Successful in 16s
All checks were successful
Run Tests on Code / run-tests (push) Successful in 16s
This commit is contained in:
commit
3e78ce5bf6
8 changed files with 275 additions and 388 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -618,9 +618,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_api_common"
|
name = "lemmy_api_common"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bed97d80c606745807e7a41d2e7a54912e6dc73b17f847453717cfa1e6693b31"
|
checksum = "17366fcde90b07f4e5a8fefa62378fe348424ba79c8e9fb3ddc63ef76d687493"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
@ -637,9 +637,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_db_schema"
|
name = "lemmy_db_schema"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a17c613a84befef3daadc179e2069e02848b83dfd80d7955ca825bdca92869b"
|
checksum = "5e2d9a0c6f8f3df4664f9479ceca138ee6217b89653bafb753a498cabc5f3ab5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -656,9 +656,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_db_views"
|
name = "lemmy_db_views"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e360aaee508cb057c6df0160b27aeb8b845a3725127b2d7e4e4c877397418539"
|
checksum = "02659eb474ab54da6296d4edb5a974c0affa5cfcf8a2fa31bb52793dedef9d5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -667,9 +667,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_db_views_actor"
|
name = "lemmy_db_views_actor"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "606962be1df35bf9214a22cea819cec181ecd4e71dfe693b92428291b69a7cd6"
|
checksum = "5187730858dc808b5cf06aadbb1d1f8ca360d4ed3c375e5606e63be4c9e24e06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
|
@ -681,9 +681,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_db_views_moderator"
|
name = "lemmy_db_views_moderator"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e64669a695c855143be2a9d4a662d481d235d7470621793db0607f60190be80"
|
checksum = "18f6fab36e1dcadc043b81c5916044ee65219d837f5d221a908296f9c55f3872"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -17,8 +17,8 @@ systemd-units = { enable = false }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "^0.4.26"
|
chrono = "^0.4.26"
|
||||||
lemmy_api_common = "0.19.1"
|
lemmy_api_common = "0.19.3"
|
||||||
lemmy_db_schema = "0.19.1"
|
lemmy_db_schema = "0.19.3"
|
||||||
once_cell = "^1.18.0"
|
once_cell = "^1.18.0"
|
||||||
reqwest = { version = "^0.11.18", features = ["blocking", "json"] }
|
reqwest = { version = "^0.11.18", features = ["blocking", "json"] }
|
||||||
serde = "^1.0.164"
|
serde = "^1.0.164"
|
||||||
|
|
278
src/bot.rs
278
src/bot.rs
|
@ -1,163 +1,163 @@
|
||||||
use crate::config::{Config, PostBody, SeriesConfig};
|
use crate::{config::{Config, PostBody, SeriesConfig}, fetchers::{jnovel}, lemmy};
|
||||||
use crate::fetchers::jnovel::JPostInfo;
|
use crate::fetchers::jnovel::JPostInfo;
|
||||||
use crate::lemmy::{Lemmy, PostInfo};
|
use crate::lemmy::{Lemmy, PostInfo};
|
||||||
use crate::post_history::SeriesHistory;
|
use crate::post_history::SeriesHistory;
|
||||||
use crate::{fetchers::{jnovel}, lemmy, write_error, write_info, write_warn, SharedData};
|
use chrono::{DateTime, Duration, Timelike, Utc};
|
||||||
use chrono::{DateTime, Duration, Utc};
|
|
||||||
use lemmy_api_common::post::CreatePost;
|
use lemmy_api_common::post::CreatePost;
|
||||||
use lemmy_db_schema::newtypes::{CommunityId, LanguageId};
|
use lemmy_db_schema::newtypes::{CommunityId, LanguageId};
|
||||||
use lemmy_db_schema::PostFeatureType;
|
use lemmy_db_schema::PostFeatureType;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use crate::fetchers::Fetcher;
|
use crate::fetchers::Fetcher;
|
||||||
|
use systemd_journal_logger::connected_to_journal;
|
||||||
|
|
||||||
pub(crate) async fn run(data: Arc<RwLock<SharedData>>) {
|
macro_rules! info {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::info!("[INFO] {}", $msg),
|
||||||
|
false => println!("[INFO] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! warn {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::warn!("[WARN] {}", $msg),
|
||||||
|
false => println!("[WARN] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::error!("[ERROR] {}", $msg),
|
||||||
|
false => eprintln!("[ERROR] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn run() {
|
||||||
let mut last_reload: DateTime<Utc>;
|
let mut last_reload: DateTime<Utc>;
|
||||||
let mut lemmy: Lemmy;
|
let mut lemmy: Lemmy;
|
||||||
let mut login_error: bool;
|
let mut login_error: bool;
|
||||||
let mut communities;
|
let mut communities: HashMap<String, CommunityId>;
|
||||||
{
|
let mut post_history: SeriesHistory;
|
||||||
let mut write = data.write().await;
|
let mut start: DateTime<Utc>;
|
||||||
|
let mut config: Config = Config::load();
|
||||||
|
last_reload = Utc::now();
|
||||||
|
|
||||||
// Errors during bot init are likely unrecoverable and therefore should panic the bot
|
lemmy = match lemmy::login(&config).await {
|
||||||
// Does not really matter since the bot will get restarted anyway but this way the uptime url logs a downtime
|
Ok(data) => data,
|
||||||
write.config = Config::load();
|
Err(_) => panic!(),
|
||||||
last_reload = Utc::now();
|
};
|
||||||
}
|
login_error = false;
|
||||||
|
|
||||||
{
|
communities = match lemmy.get_communities().await {
|
||||||
let read = data.read().await;
|
Ok(data) => data,
|
||||||
lemmy = match lemmy::login(&read.config).await {
|
Err(_) => panic!(),
|
||||||
Ok(data) => data,
|
};
|
||||||
Err(_) => panic!(),
|
|
||||||
};
|
|
||||||
login_error = false;
|
|
||||||
|
|
||||||
communities = match lemmy.get_communities().await {
|
start = Utc::now();
|
||||||
Ok(data) => data,
|
|
||||||
Err(_) => panic!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut write = data.write().await;
|
|
||||||
write.start = Utc::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
let info_msg = "Bot init successful, starting normal operations".to_owned();
|
let info_msg = "Bot init successful, starting normal operations".to_owned();
|
||||||
write_info(info_msg);
|
info!(info_msg);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
idle(&data).await;
|
idle(&start, &config).await;
|
||||||
|
start = Utc::now();
|
||||||
|
|
||||||
{
|
// replace with watcher
|
||||||
let mut write = data.write().await;
|
if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) {
|
||||||
|
config = Config::load();
|
||||||
write.start = Utc::now();
|
let message = "Config reloaded".to_owned();
|
||||||
|
info!(message);
|
||||||
if write.start - last_reload >= Duration::seconds(write.config.config_reload_seconds as i64) {
|
|
||||||
write.config = Config::load();
|
|
||||||
let message = "Config reloaded".to_owned();
|
|
||||||
write_info(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if login_error {
|
||||||
let read = data.read().await;
|
let info_msg = "Login invalid, refreshing session";
|
||||||
if login_error {
|
info!(info_msg);
|
||||||
lemmy = match lemmy::login(&read.config).await {
|
lemmy = match lemmy::login(&config).await {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
login_error = false;
|
login_error = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) {
|
||||||
let read = data.read().await;
|
communities = match lemmy.get_communities().await {
|
||||||
if read.start - last_reload >= Duration::seconds(read.config.config_reload_seconds as i64) {
|
Ok(data) => data,
|
||||||
communities = match lemmy.get_communities().await {
|
Err(_) => {
|
||||||
Ok(data) => data,
|
|
||||||
Err(_) => {
|
|
||||||
login_error = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let message = "Communities reloaded".to_owned();
|
|
||||||
write_info(message);
|
|
||||||
last_reload = Utc::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut write = data.write().await;
|
|
||||||
write.post_history = SeriesHistory::load_history();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let read = data.read().await;
|
|
||||||
let series = read.config.series.clone();
|
|
||||||
drop(read);
|
|
||||||
for series in series {
|
|
||||||
if handle_series(&series, &communities, &lemmy, &data)
|
|
||||||
.await
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
login_error = true;
|
login_error = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
|
let message = "Communities reloaded".to_owned();
|
||||||
|
info!(message);
|
||||||
|
last_reload = Utc::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
idle(&data).await;
|
post_history = SeriesHistory::load_history();
|
||||||
|
|
||||||
|
let series = config.series.clone();
|
||||||
|
for series in series {
|
||||||
|
if handle_series(&series, &communities, &lemmy, &config, &mut post_history)
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
login_error = true;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
idle(&start, &config).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn idle(data: &Arc<RwLock<SharedData>>) {
|
async fn idle(start: &DateTime<Utc>, config: &Config) {
|
||||||
let read = data.read().await;
|
|
||||||
let mut sleep_duration = Duration::seconds(30);
|
let mut sleep_duration = Duration::seconds(30);
|
||||||
if Utc::now() - read.start > sleep_duration {
|
if Utc::now() - start > sleep_duration {
|
||||||
sleep_duration = Duration::seconds(60);
|
sleep_duration = Duration::seconds(60);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(status_url) = read.config.status_post_url.clone() {
|
if let Some(status_url) = config.status_post_url.clone() {
|
||||||
match reqwest::get(status_url).await {
|
match reqwest::get(status_url).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while Utc::now() - read.start < sleep_duration {
|
while Utc::now() - start < sleep_duration {
|
||||||
sleep(Duration::milliseconds(100).to_std().unwrap()).await;
|
sleep(Duration::milliseconds(100).to_std().unwrap()).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, CommunityId>, lemmy: &Lemmy, data: &Arc<RwLock<SharedData>>) -> Result<(), ()> {
|
async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, CommunityId>, lemmy: &Lemmy, config: &Config, post_history: &mut SeriesHistory ) -> Result<(), ()> {
|
||||||
let jnc = jnovel::JFetcherOptions::new(series.slug.clone(), series.parted);
|
let jnc = jnovel::JFetcherOptions::new(series.slug.clone(), series.parted);
|
||||||
let post_list = match jnc.check_feed().await {
|
let post_list = match jnc.check_feed().await {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(_) => return Err(()),
|
Err(_) => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if post_list.is_empty() && Utc::now().minute() % 10 == 0 {
|
||||||
|
let info_msg = "No Updates found";
|
||||||
|
info!(info_msg);
|
||||||
|
}
|
||||||
|
|
||||||
for post_info in post_list.clone().iter() {
|
for post_info in post_list.clone().iter() {
|
||||||
// todo .clone() likely not needed
|
|
||||||
let post_part_info = post_info.get_part_info();
|
let post_part_info = post_info.get_part_info();
|
||||||
let post_lemmy_info = post_info.get_info();
|
let post_lemmy_info = post_info.get_info();
|
||||||
|
|
||||||
{
|
if post_history.check_for_post(
|
||||||
let read = data.read().await;
|
series.slug.as_str(),
|
||||||
if read.post_history.check_for_post(
|
post_part_info.as_string().as_str(),
|
||||||
series.slug.as_str(),
|
post_lemmy_info.title.as_str(),
|
||||||
post_part_info.as_string().as_str(),
|
) {
|
||||||
post_lemmy_info.title.as_str(),
|
continue;
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let post_series_config = match post_info {
|
let post_series_config = match post_info {
|
||||||
|
@ -190,53 +190,46 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm
|
||||||
post_lemmy_info.title.as_str(),
|
post_lemmy_info.title.as_str(),
|
||||||
post_series_config.name.as_str()
|
post_series_config.name.as_str()
|
||||||
);
|
);
|
||||||
write_info(info);
|
info!(info);
|
||||||
let post_id = lemmy.post(post_data).await?;
|
let post_id = lemmy.post(post_data).await?;
|
||||||
|
|
||||||
|
if post_series_config.pin_settings.pin_new_post_community
|
||||||
|
&& config
|
||||||
|
.protected_communities
|
||||||
|
.contains(&post_series_config.name)
|
||||||
{
|
{
|
||||||
let read = data.read().await;
|
let info = format!(
|
||||||
if post_series_config.pin_settings.pin_new_post_community
|
"Pinning '{}' to {}",
|
||||||
&& !read
|
post_lemmy_info.title,
|
||||||
.config
|
post_series_config.name.as_str()
|
||||||
.protected_communities
|
);
|
||||||
.contains(&post_series_config.name)
|
info!(info);
|
||||||
{
|
let pinned_posts = lemmy.get_community_pinned(community_id).await?;
|
||||||
let info = format!(
|
if !pinned_posts.is_empty() {
|
||||||
"Pinning '{}' to {}",
|
let community_pinned_post = &pinned_posts[0];
|
||||||
post_lemmy_info.title,
|
lemmy
|
||||||
post_series_config.name.as_str()
|
.unpin(community_pinned_post.post.id, PostFeatureType::Community)
|
||||||
);
|
.await?;
|
||||||
write_info(info);
|
|
||||||
let pinned_posts = lemmy.get_community_pinned(community_id).await?;
|
|
||||||
if !pinned_posts.is_empty() {
|
|
||||||
let community_pinned_post = &pinned_posts[0];
|
|
||||||
lemmy
|
|
||||||
.unpin(community_pinned_post.post.id, PostFeatureType::Community)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
lemmy.pin(post_id, PostFeatureType::Community).await?;
|
|
||||||
} else if read
|
|
||||||
.config
|
|
||||||
.protected_communities
|
|
||||||
.contains(&post_series_config.name)
|
|
||||||
{
|
|
||||||
let message = format!(
|
|
||||||
"Community '{}' for Series '{}' is protected. Is this intended?",
|
|
||||||
&post_series_config.name, series.slug
|
|
||||||
);
|
|
||||||
write_warn(message);
|
|
||||||
}
|
}
|
||||||
|
lemmy.pin(post_id, PostFeatureType::Community).await?;
|
||||||
|
} else if config
|
||||||
|
.protected_communities
|
||||||
|
.contains(&post_series_config.name)
|
||||||
|
{
|
||||||
|
let message = format!(
|
||||||
|
"Community '{}' for Series '{}' is protected. Is this intended?",
|
||||||
|
&post_series_config.name, series.slug
|
||||||
|
);
|
||||||
|
warn!(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let read = data.read().await;
|
|
||||||
if post_series_config.pin_settings.pin_new_post_local {
|
if post_series_config.pin_settings.pin_new_post_local {
|
||||||
let info = format!("Pinning '{}' to Instance", post_lemmy_info.title);
|
let info = format!("Pinning '{}' to Instance", post_lemmy_info.title);
|
||||||
write_info(info);
|
info!(info);
|
||||||
let pinned_posts = lemmy.get_local_pinned().await?;
|
let pinned_posts = lemmy.get_local_pinned().await?;
|
||||||
if !pinned_posts.is_empty() {
|
if !pinned_posts.is_empty() {
|
||||||
for pinned_post in pinned_posts {
|
for pinned_post in pinned_posts {
|
||||||
if read
|
if config
|
||||||
.config
|
|
||||||
.protected_communities
|
.protected_communities
|
||||||
.contains(&pinned_post.community.name)
|
.contains(&pinned_post.community.name)
|
||||||
{
|
{
|
||||||
|
@ -253,9 +246,8 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm
|
||||||
lemmy.pin(post_id, PostFeatureType::Local).await?;
|
lemmy.pin(post_id, PostFeatureType::Local).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut series_history = read.post_history.get_series(series.slug.as_str());
|
let mut series_history = post_history.get_series(series.slug.as_str());
|
||||||
let mut part_history = series_history.get_part(post_part_info.as_string().as_str());
|
let mut part_history = series_history.get_part(post_part_info.as_string().as_str());
|
||||||
drop(read);
|
|
||||||
|
|
||||||
match post_info {
|
match post_info {
|
||||||
JPostInfo::Chapter { .. } => part_history.chapter = post_info.get_info().title,
|
JPostInfo::Chapter { .. } => part_history.chapter = post_info.get_info().title,
|
||||||
|
@ -263,11 +255,9 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm
|
||||||
}
|
}
|
||||||
|
|
||||||
series_history.set_part(post_part_info.as_string().as_str(), part_history);
|
series_history.set_part(post_part_info.as_string().as_str(), part_history);
|
||||||
let mut write = data.write().await;
|
post_history
|
||||||
write
|
|
||||||
.post_history
|
|
||||||
.set_series(series.slug.as_str(), series_history);
|
.set_series(series.slug.as_str(), series_history);
|
||||||
write.post_history.save_history();
|
post_history.save_history();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{write_error, HTTP_CLIENT, lemmy};
|
use crate::{HTTP_CLIENT, lemmy};
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -10,6 +10,25 @@ use crate::fetchers::Fetcher;
|
||||||
use crate::fetchers::jnovel::JPostInfo::{Chapter, Volume};
|
use crate::fetchers::jnovel::JPostInfo::{Chapter, Volume};
|
||||||
use crate::fetchers::jnovel::PartInfo::{NoParts, Part};
|
use crate::fetchers::jnovel::PartInfo::{NoParts, Part};
|
||||||
use crate::lemmy::{PostInfo, PostInfoInner};
|
use crate::lemmy::{PostInfo, PostInfoInner};
|
||||||
|
use systemd_journal_logger::connected_to_journal;
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::error!("[ERROR] {}", $msg),
|
||||||
|
false => eprintln!("[ERROR] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! info {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::info!("[INFO] {}", $msg),
|
||||||
|
false => println!("[INFO] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static PAST_DAYS_ELIGIBLE: u8 = 4;
|
static PAST_DAYS_ELIGIBLE: u8 = 4;
|
||||||
|
|
||||||
|
@ -266,13 +285,13 @@ impl Fetcher for JFetcherOptions {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -281,7 +300,7 @@ impl Fetcher for JFetcherOptions {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -318,7 +337,7 @@ impl Fetcher for JFetcherOptions {
|
||||||
match part_number {
|
match part_number {
|
||||||
Some(number) => new_part_info = Part(number),
|
Some(number) => new_part_info = Part(number),
|
||||||
None => {
|
None => {
|
||||||
println!("No Part found, assuming 1");
|
info!("No Part found, assuming 1");
|
||||||
new_part_info = Part(1);
|
new_part_info = Part(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,13 +411,13 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -407,7 +426,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
pub mod jnovel;
|
pub mod jnovel;
|
||||||
mod tobooks;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub(crate) trait Fetcher {
|
pub(crate) trait Fetcher {
|
||||||
|
|
216
src/lemmy.rs
216
src/lemmy.rs
|
@ -1,5 +1,5 @@
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::{write_error, HTTP_CLIENT};
|
use crate::{HTTP_CLIENT};
|
||||||
use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse};
|
use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse};
|
||||||
use lemmy_api_common::lemmy_db_views::structs::PostView;
|
use lemmy_api_common::lemmy_db_views::structs::PostView;
|
||||||
use lemmy_api_common::person::{Login, LoginResponse};
|
use lemmy_api_common::person::{Login, LoginResponse};
|
||||||
|
@ -9,7 +9,18 @@ use lemmy_db_schema::newtypes::{CommunityId, PostId};
|
||||||
use lemmy_db_schema::{ListingType, PostFeatureType};
|
use lemmy_db_schema::{ListingType, PostFeatureType};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use systemd_journal_logger::connected_to_journal;
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::error!("[ERROR] {}", $msg),
|
||||||
|
false => eprintln!("[ERROR] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct Lemmy {
|
pub(crate) struct Lemmy {
|
||||||
jwt_token: Sensitive<String>,
|
jwt_token: Sensitive<String>,
|
||||||
|
@ -45,7 +56,7 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -63,14 +74,14 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> {
|
||||||
}),
|
}),
|
||||||
None => {
|
None => {
|
||||||
let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned();
|
let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned();
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status => {
|
status => {
|
||||||
let err_msg = format!("Unexpected HTTP Status '{}' during Login", status);
|
let err_msg = format!("Unexpected HTTP Status '{}' during Login", status);
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,68 +89,21 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> {
|
||||||
|
|
||||||
impl Lemmy {
|
impl Lemmy {
|
||||||
pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> {
|
pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> {
|
||||||
let response = match HTTP_CLIENT
|
let response = self.fetch_data_json("/api/v3/post", &post).await?;
|
||||||
.post(format!("{}/api/v3/post", &self.instance))
|
|
||||||
.bearer_auth(&self.jwt_token.to_string())
|
|
||||||
.json(&post)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(data) => match data.text().await {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) {
|
let json_data: PostView = self.parse_json(&response).await?;
|
||||||
Ok(mut data) => data.remove("post_view").expect("Element should be present"),
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(json_data.post.id)
|
Ok(json_data.post.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> {
|
async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> {
|
||||||
let response = match HTTP_CLIENT
|
let response = self.fetch_data_json("/api/v3/post/feature", ¶ms).await?;
|
||||||
.post(format!("{}/api/v3/post/feature", &self.instance))
|
|
||||||
.bearer_auth(&self.jwt_token.to_string())
|
|
||||||
.json(¶ms)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(data) => match data.text().await {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) {
|
let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) {
|
||||||
Ok(mut data) => data.remove("post_view").expect("Element should be present"),
|
Ok(mut data) => data.remove("post_view").expect("Element should be present"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("{e}");
|
let err_msg = format!("{e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -172,36 +136,9 @@ impl Lemmy {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = match HTTP_CLIENT
|
let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?;
|
||||||
.get(format!("{}/api/v3/post/list", &self.instance))
|
|
||||||
.bearer_auth(&self.jwt_token.to_string())
|
|
||||||
.query(&list_params)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(data) => match data.text().await {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_data: GetPostsResponse = match serde_json::from_str(&response) {
|
let json_data: GetPostsResponse = self.parse_json(&response).await?;
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(json_data
|
Ok(json_data
|
||||||
.posts
|
.posts
|
||||||
|
@ -217,36 +154,9 @@ impl Lemmy {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = match HTTP_CLIENT
|
let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?;
|
||||||
.get(format!("{}/api/v3/post/list", &self.instance))
|
|
||||||
.bearer_auth(&self.jwt_token.to_string())
|
|
||||||
.query(&list_params)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(data) => match data.text().await {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_data: GetPostsResponse = match serde_json::from_str(&response) {
|
let json_data: GetPostsResponse = self.parse_json(&response).await?;
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(json_data
|
Ok(json_data
|
||||||
.posts
|
.posts
|
||||||
|
@ -262,36 +172,9 @@ impl Lemmy {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = match HTTP_CLIENT
|
let response = self.fetch_data_query("/api/v3/community/list", &list_params).await?;
|
||||||
.get(format!("{}/api/v3/community/list", &self.instance))
|
|
||||||
.bearer_auth(&self.jwt_token.to_string())
|
|
||||||
.query(&list_params)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(data) => match data.text().await {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_data: ListCommunitiesResponse = match serde_json::from_str(&response) {
|
let json_data: ListCommunitiesResponse = self.parse_json(&response).await?;
|
||||||
Ok(data) => data,
|
|
||||||
Err(e) => {
|
|
||||||
let err_msg = format!("{e}");
|
|
||||||
write_error(err_msg);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut communities: HashMap<String, CommunityId> = HashMap::new();
|
let mut communities: HashMap<String, CommunityId> = HashMap::new();
|
||||||
for community_view in json_data.communities {
|
for community_view in json_data.communities {
|
||||||
|
@ -301,4 +184,53 @@ impl Lemmy {
|
||||||
|
|
||||||
Ok(communities)
|
Ok(communities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> {
|
||||||
|
let res = HTTP_CLIENT
|
||||||
|
.post(format!("{}{route}", self.instance))
|
||||||
|
.bearer_auth(&self.jwt_token.to_string())
|
||||||
|
.json(&json)
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
self.extract_data(res).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_data_query<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> {
|
||||||
|
let res = HTTP_CLIENT
|
||||||
|
.post(format!("{}{route}", self.instance))
|
||||||
|
.bearer_auth(&self.jwt_token.to_string())
|
||||||
|
.query(&json)
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
self.extract_data(res).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Result<String,()> {
|
||||||
|
match response {
|
||||||
|
Ok(data) => match data.text().await {
|
||||||
|
Ok(data) => Ok(data),
|
||||||
|
Err(e) => {
|
||||||
|
let err_msg = format!("{e}");
|
||||||
|
error!(err_msg);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let err_msg = format!("{e}");
|
||||||
|
error!(err_msg);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> {
|
||||||
|
match serde_json::from_str::<HashMap<&str, T>>(response) {
|
||||||
|
Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")),
|
||||||
|
Err(e) => {
|
||||||
|
let err_msg = format!("{e}");
|
||||||
|
error!(err_msg);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
83
src/main.rs
83
src/main.rs
|
@ -1,15 +1,8 @@
|
||||||
use crate::config::Config;
|
use chrono::{Duration};
|
||||||
use crate::post_history::SeriesHistory;
|
use log::{LevelFilter};
|
||||||
use chrono::{DateTime, Duration, Utc};
|
|
||||||
use log::{error, info, warn, LevelFilter};
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use std::collections::HashMap;
|
use systemd_journal_logger::{JournalLog};
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use systemd_journal_logger::{connected_to_journal, JournalLog};
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use tokio::time::sleep;
|
|
||||||
|
|
||||||
mod bot;
|
mod bot;
|
||||||
mod config;
|
mod config;
|
||||||
|
@ -17,27 +10,6 @@ mod lemmy;
|
||||||
mod post_history;
|
mod post_history;
|
||||||
mod fetchers;
|
mod fetchers;
|
||||||
|
|
||||||
pub(crate) fn write_error(err_msg: String) {
|
|
||||||
match connected_to_journal() {
|
|
||||||
true => error!("[ERROR] {err_msg}"),
|
|
||||||
false => println!("[ERROR] {err_msg}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_warn(warn_msg: String) {
|
|
||||||
match connected_to_journal() {
|
|
||||||
true => warn!("[WARN] {warn_msg}"),
|
|
||||||
false => println!("[WARN] {warn_msg}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_info(info_msg: String) {
|
|
||||||
match connected_to_journal() {
|
|
||||||
true => info!("[INFO] {info_msg}"),
|
|
||||||
false => println!("[INFO] {info_msg}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| {
|
pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| {
|
||||||
Client::builder()
|
Client::builder()
|
||||||
.timeout(Duration::seconds(30).to_std().unwrap())
|
.timeout(Duration::seconds(30).to_std().unwrap())
|
||||||
|
@ -46,25 +18,6 @@ pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| {
|
||||||
.expect("build client")
|
.expect("build client")
|
||||||
});
|
});
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub(crate) struct SharedData {
|
|
||||||
config: Config,
|
|
||||||
post_history: SeriesHistory,
|
|
||||||
start: DateTime<Utc>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SharedData {
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
SharedData {
|
|
||||||
config: Config::default(),
|
|
||||||
post_history: SeriesHistory {
|
|
||||||
series: HashMap::new(),
|
|
||||||
},
|
|
||||||
start: Utc::now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
JournalLog::new()
|
JournalLog::new()
|
||||||
|
@ -72,33 +25,5 @@ async fn main() {
|
||||||
.install()
|
.install()
|
||||||
.expect("Systemd-Logger crate error");
|
.expect("Systemd-Logger crate error");
|
||||||
log::set_max_level(LevelFilter::Info);
|
log::set_max_level(LevelFilter::Info);
|
||||||
|
bot::run().await;
|
||||||
let mut data = SharedData::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let write_data = Arc::new(RwLock::new(data.clone()));
|
|
||||||
//let read_data = write_data.clone();
|
|
||||||
let persistent_data = write_data.clone();
|
|
||||||
|
|
||||||
let bot_thread = tokio::spawn(async move { bot::run(write_data).await });
|
|
||||||
|
|
||||||
let _ = bot_thread.await;
|
|
||||||
|
|
||||||
data = persistent_data.read().await.clone();
|
|
||||||
|
|
||||||
{
|
|
||||||
let err_msg = "Bot crashed due to unknown Error, restarting thread after wait...";
|
|
||||||
match connected_to_journal() {
|
|
||||||
true => error!("[ERROR] {err_msg}"),
|
|
||||||
false => println!("[ERROR] {err_msg}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(
|
|
||||||
Duration::seconds(5)
|
|
||||||
.to_std()
|
|
||||||
.expect("Conversion should always work since static"),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
use crate::write_error;
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use systemd_journal_logger::connected_to_journal;
|
||||||
|
|
||||||
|
macro_rules! info {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::info!("[INFO] {}", $msg),
|
||||||
|
false => println!("[INFO] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($msg:tt) => {
|
||||||
|
match connected_to_journal() {
|
||||||
|
true => log::error!("[ERROR] {}", $msg),
|
||||||
|
false => eprintln!("[ERROR] {}", $msg),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||||
pub(crate) struct SeriesHistory {
|
pub(crate) struct SeriesHistory {
|
||||||
|
@ -9,6 +27,8 @@ pub(crate) struct SeriesHistory {
|
||||||
|
|
||||||
impl SeriesHistory {
|
impl SeriesHistory {
|
||||||
pub(crate) fn load_history() -> Self {
|
pub(crate) fn load_history() -> Self {
|
||||||
|
let info_msg = "Loading History";
|
||||||
|
info!(info_msg);
|
||||||
match confy::load(env!("CARGO_PKG_NAME"), "history") {
|
match confy::load(env!("CARGO_PKG_NAME"), "history") {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => panic!("history.toml not found: {e}"),
|
Err(e) => panic!("history.toml not found: {e}"),
|
||||||
|
@ -16,9 +36,11 @@ impl SeriesHistory {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn save_history(&self) {
|
pub(crate) fn save_history(&self) {
|
||||||
|
let info_msg = "Saving History";
|
||||||
|
info!(info_msg);
|
||||||
if let Err(e) = confy::store(env!("CARGO_PKG_NAME"), "history", self) {
|
if let Err(e) = confy::store(env!("CARGO_PKG_NAME"), "history", self) {
|
||||||
let err_msg = format!("Unexpected error saving to history.toml: {e}");
|
let err_msg = format!("Unexpected error saving to history.toml: {e}");
|
||||||
write_error(err_msg);
|
error!(err_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue