parse datetimes properly
This commit is contained in:
parent
adda135743
commit
a8c0be2c05
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -61,6 +61,7 @@ dependencies = [
|
|||||||
"sea-orm",
|
"sea-orm",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -11,6 +11,7 @@ rumqttc = "0.24.0"
|
|||||||
sea-orm = { version = "0.12", features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros" ] }
|
sea-orm = { version = "0.12", features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros" ] }
|
||||||
serde = "1.0.199"
|
serde = "1.0.199"
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
|
time = { version = "0.3.36", features = ["macros", "serde", "formatting", "parsing" ] }
|
||||||
tokio = { version = "1.37.0", features = ["full"] }
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
7
src/alert_swiss.rs
Normal file
7
src/alert_swiss.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use crate::json::alerts::Alerts;
|
||||||
|
|
||||||
|
const ALERT_SWISS_URL: &str = "https://www.alert.swiss/content/alertswiss-internet/en/home/_jcr_content/polyalert.alertswiss_alerts.actual.json";
|
||||||
|
|
||||||
|
pub async fn fetch_alerts() -> Result<Alerts, reqwest::Error> {
|
||||||
|
reqwest::get(ALERT_SWISS_URL).await?.json::<Alerts>().await
|
||||||
|
}
|
12
src/cli.rs
Normal file
12
src/cli.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//! Cli interface.
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
/// Push Alertswiss notifications to MQTT.
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
pub struct Cli {
|
||||||
|
/// Update interval in seconds
|
||||||
|
#[arg(short, long, default_value_t = 10)]
|
||||||
|
pub interval: u64,
|
||||||
|
}
|
15
src/config.rs
Normal file
15
src/config.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use crate::cli::Cli;
|
||||||
|
|
||||||
|
/// Application configuration.
|
||||||
|
pub struct Config {
|
||||||
|
/// Update interval in seconds
|
||||||
|
pub interval: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Cli> for Config {
|
||||||
|
fn from(value: Cli) -> Self {
|
||||||
|
Self {
|
||||||
|
interval: value.interval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use time::PrimitiveDateTime;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
area::Area, contact::Contact, description::Description, image::Image,
|
area::Area, contact::Contact, description::Description, image::Image,
|
||||||
@ -11,7 +12,8 @@ use super::{
|
|||||||
pub struct Alert {
|
pub struct Alert {
|
||||||
pub identifier: String,
|
pub identifier: String,
|
||||||
pub gtrans_origin: Option<String>,
|
pub gtrans_origin: Option<String>,
|
||||||
pub sent: String,
|
#[serde(deserialize_with = "super::datetime::deserialize_alert")]
|
||||||
|
pub sent: PrimitiveDateTime,
|
||||||
pub title: Title,
|
pub title: Title,
|
||||||
pub description: Description,
|
pub description: Description,
|
||||||
pub nation_wide: bool,
|
pub nation_wide: bool,
|
||||||
@ -27,7 +29,8 @@ pub struct Alert {
|
|||||||
pub severity: String,
|
pub severity: String,
|
||||||
pub test_alert: bool,
|
pub test_alert: bool,
|
||||||
pub technical_test_alert: bool,
|
pub technical_test_alert: bool,
|
||||||
pub publish_date: String,
|
#[serde(deserialize_with = "super::datetime::deserialize_alert")]
|
||||||
|
pub publish_date: PrimitiveDateTime,
|
||||||
pub areas: Vec<Area>,
|
pub areas: Vec<Area>,
|
||||||
pub images: Vec<Image>,
|
pub images: Vec<Image>,
|
||||||
pub image_titles: Vec<ImageTitle>,
|
pub image_titles: Vec<ImageTitle>,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
use super::alert::Alert;
|
use super::alert::Alert;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Alerts {
|
pub struct Alerts {
|
||||||
pub heartbeat_age_in_millis: u64,
|
pub heartbeat_age_in_millis: u64,
|
||||||
pub render_time: String,
|
#[serde(deserialize_with = "super::datetime::deserialize_alerts")]
|
||||||
pub alerts: Vec<Alert>,
|
pub render_time: OffsetDateTime,
|
||||||
|
#[serde(rename = "alerts")]
|
||||||
|
pub list: Vec<Alert>,
|
||||||
}
|
}
|
||||||
|
26
src/json/datetime.rs
Normal file
26
src/json/datetime.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use time::format_description::FormatItem;
|
||||||
|
use time::macros::format_description;
|
||||||
|
use time::{OffsetDateTime, PrimitiveDateTime};
|
||||||
|
|
||||||
|
const ALERT_FORMAT: &[FormatItem<'_>] =
|
||||||
|
format_description!("[weekday repr:short], [day].[month].[year], [hour]:[minute]");
|
||||||
|
const ALERTS_FORMAT: &[FormatItem<'_>] = format_description!(
|
||||||
|
"[day].[month].[year] [hour]:[minute]:[second].[subsecond] [offset_hour sign:mandatory][offset_minute]"
|
||||||
|
);
|
||||||
|
|
||||||
|
pub fn deserialize_alert<'de, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s: &str = Deserialize::deserialize(deserializer)?;
|
||||||
|
PrimitiveDateTime::parse(s, ALERT_FORMAT).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_alerts<'de, D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s: &str = Deserialize::deserialize(deserializer)?;
|
||||||
|
OffsetDateTime::parse(s, ALERTS_FORMAT).map_err(serde::de::Error::custom)
|
||||||
|
}
|
42
src/lib.rs
Normal file
42
src/lib.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use config::Config;
|
||||||
|
use tokio::time;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::json::alert::Alert;
|
||||||
|
|
||||||
|
pub mod alert_swiss;
|
||||||
|
pub mod cli;
|
||||||
|
pub mod config;
|
||||||
|
mod json {
|
||||||
|
pub mod alert;
|
||||||
|
pub mod alerts;
|
||||||
|
pub mod area;
|
||||||
|
pub mod circle;
|
||||||
|
pub mod contact;
|
||||||
|
pub mod coordinate;
|
||||||
|
pub mod datetime;
|
||||||
|
pub mod description;
|
||||||
|
pub mod image;
|
||||||
|
pub mod image_description;
|
||||||
|
pub mod image_title;
|
||||||
|
pub mod link;
|
||||||
|
pub mod polygon;
|
||||||
|
pub mod region;
|
||||||
|
pub mod text;
|
||||||
|
pub mod title;
|
||||||
|
}
|
||||||
|
pub mod logging;
|
||||||
|
|
||||||
|
pub async fn run(config: Config) {
|
||||||
|
let mut interval = time::interval(Duration::from_secs(config.interval));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
let alerts = alert_swiss::fetch_alerts().await.unwrap();
|
||||||
|
let new_alerts: Vec<Alert> = alerts.list.into_iter().filter(|x| true).collect();
|
||||||
|
|
||||||
|
debug!("{new_alerts:#?}");
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
pub(crate) fn setup(bin_name: &str) {
|
pub fn setup(bin_name: &str) {
|
||||||
let default_config = format!("{}=info,tower_http=info", bin_name);
|
let default_config = format!("{}=info,tower_http=info", bin_name);
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(
|
.with(
|
||||||
|
44
src/main.rs
44
src/main.rs
@ -1,42 +1,16 @@
|
|||||||
use std::time::Duration;
|
use alert_me::{cli::Cli, logging};
|
||||||
|
use clap::Parser;
|
||||||
use tokio::time;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use crate::json::alerts::Alerts;
|
|
||||||
|
|
||||||
mod json {
|
|
||||||
pub mod alert;
|
|
||||||
pub mod alerts;
|
|
||||||
pub mod area;
|
|
||||||
pub mod circle;
|
|
||||||
pub mod contact;
|
|
||||||
pub mod coordinate;
|
|
||||||
pub mod description;
|
|
||||||
pub mod image;
|
|
||||||
pub mod image_description;
|
|
||||||
pub mod image_title;
|
|
||||||
pub mod link;
|
|
||||||
pub mod polygon;
|
|
||||||
pub mod region;
|
|
||||||
pub mod text;
|
|
||||||
pub mod title;
|
|
||||||
}
|
|
||||||
mod logging;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
if std::env::var_os("RUST_LOG").is_none() {
|
||||||
|
std::env::set_var("RUST_LOG", "info");
|
||||||
|
}
|
||||||
|
|
||||||
logging::setup("alert-me");
|
logging::setup("alert-me");
|
||||||
|
|
||||||
let mut interval = time::interval(Duration::from_secs(5));
|
let args = Cli::parse();
|
||||||
|
let config = args.into();
|
||||||
|
|
||||||
loop {
|
alert_me::run(config).await
|
||||||
interval.tick().await;
|
|
||||||
let resp = reqwest::get("https://www.alert.swiss/content/alertswiss-internet/en/home/_jcr_content/polyalert.alertswiss_alerts.actual.json")
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.json::<Alerts>()
|
|
||||||
.await.unwrap();
|
|
||||||
debug!("{resp:#?}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user