aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormicwoj92 <45581170+micwoj92@users.noreply.github.com>2023-11-21 20:16:20 +0100
committerGitHub <noreply@github.com>2023-11-21 20:16:20 +0100
commit342064df385632d50854f1d52147505297f19a04 (patch)
tree8ae17fa304c23bdcab7827122366547aef61d3f0
parent09ce40640757c764ce9be124a689ae244d0a2112 (diff)
downloadRSS-watcher-342064df385632d50854f1d52147505297f19a04.tar.gz
RSS-watcher-342064df385632d50854f1d52147505297f19a04.zip
format code
-rw-r--r--src/database.rs63
-rw-r--r--src/main.rs44
-rw-r--r--src/notify.rs26
-rw-r--r--src/rss_utils.rs123
4 files changed, 155 insertions, 101 deletions
diff --git a/src/database.rs b/src/database.rs
index 2cd3c3f..c48bc97 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -1,8 +1,8 @@
-use std::process;
-use std::env;
-use log::{debug, info, warn, error};
-use mysql::*;
+use log::{debug, error, info, warn};
use mysql::prelude::*;
+use mysql::*;
+use std::env;
+use std::process;
#[derive(Debug, PartialEq, Eq)]
pub struct FeedConf {
@@ -12,7 +12,7 @@ pub struct FeedConf {
pub title: String,
pub message: String,
pub push_url: String,
- pub push_token: String
+ pub push_token: String,
}
/**
@@ -23,11 +23,13 @@ fn build_opts() -> Opts {
let db_base = env::var("DB_BASE").expect("$DB_BASE is not set");
let db_user = env::var("DB_USER").expect("$DB_USER is not set");
let db_pass = env::var("DB_PASS").expect("$DB_PASS is not set");
- return Opts::from(OptsBuilder::new()
+ return Opts::from(
+ OptsBuilder::new()
.ip_or_hostname(Some(db_host))
.user(Some(db_user))
.pass(Some(db_pass))
- .db_name(Some(db_base)));
+ .db_name(Some(db_base)),
+ );
}
pub fn new_conn() -> Option<Conn> {
@@ -44,13 +46,18 @@ pub fn new_conn() -> Option<Conn> {
*/
fn table_exists(conn: &mut Conn) -> bool {
let db_base = env::var("DB_BASE").expect("$DB_BASE is not set");
- let q = conn.prep("SELECT table_name \
+ let q = conn
+ .prep(
+ "SELECT table_name \
FROM INFORMATION_SCHEMA.TABLES \
WHERE TABLE_SCHEMA=:schema \
- AND TABLE_NAME='rss-watcher-feeds'").unwrap();
- let res: Option<String> = conn.exec_first(
- &q, params! {"schema" => db_base}).unwrap();
- if let None = res { return false; }
+ AND TABLE_NAME='rss-watcher-feeds'",
+ )
+ .unwrap();
+ let res: Option<String> = conn.exec_first(&q, params! {"schema" => db_base}).unwrap();
+ if let None = res {
+ return false;
+ }
return true;
}
@@ -91,7 +98,6 @@ fn table_create(conn: &mut Conn) {
error!("Could not create table! ({:#?}", x);
process::exit(1);
}
-
}
/**
@@ -150,7 +156,7 @@ pub fn bootstrap() {
}
let mut conn = conn_res.unwrap();
info!("Connected to database");
-
+
if !table_exists(&mut conn) {
table_create(&mut conn);
}
@@ -159,7 +165,10 @@ pub fn bootstrap() {
if version < 2 {
let res_tx = conn.start_transaction(TxOpts::default());
if let Err(x) = res_tx {
- error!("Could not create transaction for updating last fetch time! {:#?}", x);
+ error!(
+ "Could not create transaction for updating last fetch time! {:#?}",
+ x
+ );
return;
}
let mut tx = res_tx.unwrap();
@@ -191,10 +200,18 @@ pub fn get_feeds(conn: &mut Conn) -> Option<Vec<FeedConf>> {
`push_token` \
FROM `rss-watcher-feeds` \
WHERE `url` NOT LIKE 'version'";
- let res = conn.query_map(q,
- |(id,url,last_fetch,title,message,push_url,push_token)| {
- FeedConf{id,url,last_fetch,title,message,push_url,push_token}
- },);
+ let res = conn.query_map(
+ q,
+ |(id, url, last_fetch, title, message, push_url, push_token)| FeedConf {
+ id,
+ url,
+ last_fetch,
+ title,
+ message,
+ push_url,
+ push_token,
+ },
+ );
debug!("{:#?}", res);
match res {
Ok(r) => return Some(r),
@@ -211,17 +228,19 @@ pub fn get_feeds(conn: &mut Conn) -> Option<Vec<FeedConf>> {
pub fn update_last_fetch(feed_id: u32, last_fetch: i64, conn: &mut Conn) {
let res_tx = conn.start_transaction(TxOpts::default());
if let Err(x) = res_tx {
- error!("Could not create transaction for updating last fetch time! {:#?}", x);
+ error!(
+ "Could not create transaction for updating last fetch time! {:#?}",
+ x
+ );
return;
}
let mut tx = res_tx.unwrap();
let q = "UPDATE `rss-watcher-feeds` SET last_fetch=? WHERE id=?";
- if let Err(x) = tx.exec_drop(q, (last_fetch,feed_id,)) {
+ if let Err(x) = tx.exec_drop(q, (last_fetch, feed_id)) {
warn!("Could not update last fetch time...! ({:#?}", x);
}
if let Err(x) = tx.commit() {
warn!("Could not commit update! ({:#?}", x);
}
-
}
diff --git a/src/main.rs b/src/main.rs
index a523b4c..55a6557 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,16 +1,16 @@
-mod rss_utils;
-mod notify;
mod database;
+mod notify;
+mod rss_utils;
use database::FeedConf;
+use log::{debug, error, info, warn};
use std::env;
use std::process;
-use log::{debug, info, warn, error};
-use chrono::prelude::{Utc,DateTime,NaiveDateTime};
-use tokio::{time};
-use std::time::Duration;
+use chrono::prelude::{DateTime, NaiveDateTime, Utc};
use feed_rs::model::Feed;
+use std::time::Duration;
+use tokio::time;
/**
* This calls fetch_feed, and figures out wether it succeeded or not.
@@ -22,8 +22,12 @@ async fn get_feed(feed_conf: &FeedConf) -> bool {
// time as that. Which means that no articles will be found.
let last_fetch_time;
match &feed_conf.last_fetch {
- Some(x) => last_fetch_time = DateTime::from_utc(
- NaiveDateTime::from_timestamp_opt(x.to_owned(),0).unwrap(), Utc),
+ Some(x) => {
+ last_fetch_time = DateTime::from_utc(
+ NaiveDateTime::from_timestamp_opt(x.to_owned(), 0).unwrap(),
+ Utc,
+ )
+ }
None => last_fetch_time = Utc::now(),
}
debug!("Using last_fetch_time {:?}", last_fetch_time.to_owned());
@@ -32,16 +36,18 @@ async fn get_feed(feed_conf: &FeedConf) -> bool {
let res = rss_utils::fetch_feed(&feed_conf, last_fetch_time).await;
let feed_res: Option<Feed>;
match res {
- Err(e) => {
+ Err(e) => {
error!("Could not fetch feed ({:?})", e);
return false;
- },
- Ok(x) => feed_res = x
+ }
+ Ok(x) => feed_res = x,
}
- // If feed is empty (we got status code 304), we should skip any further
+ // If feed is empty (we got status code 304), we should skip any further
// processing
- if let None = feed_res { return false; }
+ if let None = feed_res {
+ return false;
+ }
let feed = feed_res.unwrap();
// Process all entries in the feed
@@ -57,13 +63,15 @@ async fn main_loop() {
let res_conn = database::new_conn();
if let None = res_conn {
- error!("Could not open database connection, waiting until next iteration before trying again!");
+ error!(
+ "Could not open database connection, waiting until next iteration before trying again!"
+ );
return;
};
let mut conn = res_conn.unwrap();
let res_feeds = database::get_feeds(&mut conn);
-
+
if let None = res_feeds {
error!("Could not get feeds, waiting until next iteration before trying again!");
return;
@@ -80,7 +88,7 @@ async fn main_loop() {
}
}
-/**
+/**
* Main app, sets up database, and then it keeps an active loop.
*/
async fn app() {
@@ -95,11 +103,11 @@ async fn app() {
process::exit(1);
}
interval_timeout = res.unwrap();
- },
+ }
Err(_e) => {
warn!("$FETCH_INTERVAL not set, using default of 2m");
interval_timeout = 120000;
- },
+ }
}
let mut interval = time::interval(Duration::from_millis(interval_timeout));
diff --git a/src/notify.rs b/src/notify.rs
index 19915db..9d7e81b 100644
--- a/src/notify.rs
+++ b/src/notify.rs
@@ -1,14 +1,19 @@
use crate::database::FeedConf;
use crate::rss_utils;
-use log::{info, error};
+use chrono::prelude::{DateTime, Utc};
use feed_rs::model::Feed;
-use chrono::prelude::{Utc,DateTime};
+use log::{error, info};
/**
* Push feed entry to gotify
*/
-async fn gotify(title: String, message: String, link: Option<String>, feed_conf: &FeedConf) -> Result<(), reqwest::Error> {
+async fn gotify(
+ title: String,
+ message: String,
+ link: Option<String>,
+ feed_conf: &FeedConf,
+) -> Result<(), reqwest::Error> {
let uri = format!("{}/message", &feed_conf.push_url);
// Build json string that will be sent as payload to gotify
@@ -17,7 +22,7 @@ async fn gotify(title: String, message: String, link: Option<String>, feed_conf:
req.push_str(format!("\"title\":\"{}\"", title).as_str());
req.push_str(format!(",\"message\":\"{}\"", message).as_str());
req.push_str(",\"priority\":1");
-
+
req.push_str(",\"extras\": {");
req.push_str("\"client::display\": { \"contentType\": \"text/markdown\" }");
if link.is_some() {
@@ -29,12 +34,13 @@ async fn gotify(title: String, message: String, link: Option<String>, feed_conf:
// Send request to gotify
let client = reqwest::Client::new();
- let res = client.post(uri)
- .query(&[("token",&feed_conf.push_token)])
- .body(req.to_owned())
- .header("Content-Type", "application/json")
- .send()
- .await?;
+ let res = client
+ .post(uri)
+ .query(&[("token", &feed_conf.push_token)])
+ .body(req.to_owned())
+ .header("Content-Type", "application/json")
+ .send()
+ .await?;
if res.status().is_success() {
info!("Sent notification with title \"{}\"", title);
} else {
diff --git a/src/rss_utils.rs b/src/rss_utils.rs
index bce412d..823f6a3 100644
--- a/src/rss_utils.rs
+++ b/src/rss_utils.rs
@@ -1,23 +1,30 @@
use crate::database::FeedConf;
-use log::{debug, info};
-use std::error::Error;
-use feed_rs::parser;
+use chrono::prelude::{DateTime, Utc};
use feed_rs::model;
-use chrono::prelude::{Utc,DateTime};
+use feed_rs::parser;
use html2md;
+use log::{debug, info};
+use std::error::Error;
extern crate mime;
/**
* Extract text field from Option
*/
fn extract_text(text: &Option<model::Text>, field: &str) -> String {
- if text.is_none() { return String::from(format!("Field {:#?} was not in feed", field)); }
+ if text.is_none() {
+ return String::from(format!("Field {:#?} was not in feed", field));
+ }
let field = text.as_ref().unwrap();
match (field.content_type.type_(), field.content_type.subtype()) {
(mime::TEXT, mime::HTML) => return html2md::parse_html(field.content.as_ref()),
(mime::TEXT, mime::PLAIN) => return field.content.to_owned(),
- _ => return String::from(format!("Unknown field content type {:#?}", field.content_type)),
+ _ => {
+ return String::from(format!(
+ "Unknown field content type {:#?}",
+ field.content_type
+ ))
+ }
}
}
@@ -25,7 +32,9 @@ fn extract_text(text: &Option<model::Text>, field: &str) -> String {
* Extract string field from Option
*/
fn extract_string(text: &Option<String>, field: &str) -> String {
- if text.is_none() { return String::from(format!("Field {:#?} was not in feed", field)); }
+ if text.is_none() {
+ return String::from(format!("Field {:#?} was not in feed", field));
+ }
return text.as_ref().unwrap().to_owned();
}
@@ -33,7 +42,9 @@ fn extract_string(text: &Option<String>, field: &str) -> String {
* Extract string field from Option
*/
fn extract_datetime(date: &Option<DateTime<Utc>>, field: &str) -> String {
- if date.is_none() { return String::from(format!("Field {:#?} was not in feed", field)); }
+ if date.is_none() {
+ return String::from(format!("Field {:#?} was not in feed", field));
+ }
return date.unwrap().to_rfc2822().replace("+0000", "UTC");
}
@@ -45,25 +56,28 @@ fn person_vec_to_md(person_vec: &Vec<model::Person>) -> String {
for (i, person) in person_vec.iter().enumerate() {
if person.uri.is_some() && person.email.is_some() {
- md_str.push_str(format!("[{}]({}) - [homepage]({})",
- person.name,
- person.email.as_ref().unwrap(),
- person.uri.as_ref().unwrap()
- ).as_str());
+ md_str.push_str(
+ format!(
+ "[{}]({}) - [homepage]({})",
+ person.name,
+ person.email.as_ref().unwrap(),
+ person.uri.as_ref().unwrap()
+ )
+ .as_str(),
+ );
} else if person.uri.is_some() {
- md_str.push_str(format!("[{}]({})",
- person.name,
- person.uri.as_ref().unwrap(),
- ).as_str());
+ md_str
+ .push_str(format!("[{}]({})", person.name, person.uri.as_ref().unwrap(),).as_str());
} else if person.email.is_some() {
- md_str.push_str(format!("[{}]({})",
- person.name,
- person.email.as_ref().unwrap(),
- ).as_str());
+ md_str.push_str(
+ format!("[{}]({})", person.name, person.email.as_ref().unwrap(),).as_str(),
+ );
} else {
md_str.push_str(&person.name);
}
- if i < (person_vec.len() - 1) { md_str.push_str(", "); }
+ if i < (person_vec.len() - 1) {
+ md_str.push_str(", ");
+ }
}
return md_str;
}
@@ -76,19 +90,16 @@ fn link_vec_to_md(link_vec: &Vec<model::Link>) -> String {
for (i, link) in link_vec.iter().enumerate() {
if link.title.is_some() {
- md_str.push_str(format!("[{}]({})",
- &link.title.as_ref().unwrap(),
- &link.href).as_str());
+ md_str
+ .push_str(format!("[{}]({})", &link.title.as_ref().unwrap(), &link.href).as_str());
} else if link.rel.is_some() {
- md_str.push_str(format!("[{}]({})",
- &link.rel.as_ref().unwrap(),
- &link.href).as_str());
+ md_str.push_str(format!("[{}]({})", &link.rel.as_ref().unwrap(), &link.href).as_str());
} else {
- md_str.push_str(format!("[{}]({})",
- &link.href,
- &link.href).as_str());
+ md_str.push_str(format!("[{}]({})", &link.href, &link.href).as_str());
+ }
+ if i < (link_vec.len() - 1) {
+ md_str.push_str(", ");
}
- if i < (link_vec.len() - 1) { md_str.push_str(", "); }
}
return md_str;
}
@@ -105,7 +116,9 @@ fn category_vec_to_md(category_vec: &Vec<model::Category>) -> String {
} else {
md_str.push_str(&category.term);
}
- if i < (category_vec.len() - 1) { md_str.push_str(", "); }
+ if i < (category_vec.len() - 1) {
+ md_str.push_str(", ");
+ }
}
return md_str;
}
@@ -139,7 +152,7 @@ fn fill_template_field(field: &str, entry: &model::Entry, feed: &model::Feed) ->
"entry.published" => return extract_datetime(&entry.published, field).to_owned(),
"entry.source" => return extract_string(&entry.source, field).to_owned(),
"entry.rights" => return extract_text(&entry.rights, field).to_owned(),
- _ => return String::from(format!("Unknown field {:#?}", field))
+ _ => return String::from(format!("Unknown field {:#?}", field)),
}
}
@@ -148,12 +161,13 @@ fn fill_template_field(field: &str, entry: &model::Entry, feed: &model::Feed) ->
* special HTML characters.
*/
pub fn escape(input: String) -> String {
- return input.replace("\\","\\\\")
- .replace("\"", "\\\"")
- .replace("\n", "\\n")
- .replace("<", "&lt;")
- .replace(">", "&gt;")
- .replace("&", "$amp;");
+ return input
+ .replace("\\", "\\\\")
+ .replace("\"", "\\\"")
+ .replace("\n", "\\n")
+ .replace("<", "&lt;")
+ .replace(">", "&gt;")
+ .replace("&", "$amp;");
}
/**
@@ -173,9 +187,7 @@ pub fn fill_template(template_str: &str, entry: &model::Entry, feed: &model::Fee
if c == '}' {
r_bracket_n += 1;
if r_bracket_n > 1 {
- filled_str.push_str(fill_template_field(&field,
- &entry,
- &feed).as_str());
+ filled_str.push_str(fill_template_field(&field, &entry, &feed).as_str());
field = "".to_owned();
r_bracket_n = 0;
l_bracket_n = 0;
@@ -185,7 +197,9 @@ pub fn fill_template(template_str: &str, entry: &model::Entry, feed: &model::Fee
}
} else if c == '{' {
l_bracket_n += 1;
- if l_bracket_n > 1 { field = "".to_owned(); }
+ if l_bracket_n > 1 {
+ field = "".to_owned();
+ }
} else {
l_bracket_n = 0;
filled_str.push(c);
@@ -196,18 +210,25 @@ pub fn fill_template(template_str: &str, entry: &model::Entry, feed: &model::Fee
/**
* Function takes a FeedConf struct, and makes a get request to fetch
- * the feed. It then uses feed_rs to parse that feed and returns that
+ * the feed. It then uses feed_rs to parse that feed and returns that
* parsed feed.
*/
-pub async fn fetch_feed(feed_conf: &FeedConf, last_fetch_time: DateTime<Utc>) -> Result<Option<model::Feed>, Box<dyn Error>> {
+pub async fn fetch_feed(
+ feed_conf: &FeedConf,
+ last_fetch_time: DateTime<Utc>,
+) -> Result<Option<model::Feed>, Box<dyn Error>> {
info!("Fetching feed \"{}\"", &feed_conf.url);
let client = reqwest::Client::new();
let last_fetch_rfc2822 = last_fetch_time.to_rfc2822().replace("+0000", "GMT");
- debug!("Using header \"If-Modified-Since {:?}\"", &last_fetch_rfc2822);
- let resp = client.get(&feed_conf.url)
- .header("If-Modified-Since", &last_fetch_rfc2822)
- .send()
- .await?;
+ debug!(
+ "Using header \"If-Modified-Since {:?}\"",
+ &last_fetch_rfc2822
+ );
+ let resp = client
+ .get(&feed_conf.url)
+ .header("If-Modified-Since", &last_fetch_rfc2822)
+ .send()
+ .await?;
if resp.status() == 304 {
info!("No changes since last fetch at {}", &last_fetch_rfc2822);
Ok(None)