cbor serializing of alerts
This commit is contained in:
parent
84dcea771d
commit
7546d06a4d
39
Cargo.lock
generated
39
Cargo.lock
generated
@ -54,10 +54,12 @@ dependencies = [
|
|||||||
name = "alert-me"
|
name = "alert-me"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ciborium",
|
||||||
"clap",
|
"clap",
|
||||||
"config",
|
"config",
|
||||||
"entity",
|
"entity",
|
||||||
"futures",
|
"futures",
|
||||||
|
"itertools",
|
||||||
"migration",
|
"migration",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rumqttc",
|
"rumqttc",
|
||||||
@ -550,6 +552,33 @@ dependencies = [
|
|||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.4"
|
version = "4.5.4"
|
||||||
@ -1109,6 +1138,16 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
@ -6,9 +6,11 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
entity = { path = "../entity" }
|
entity = { path = "../entity" }
|
||||||
migration = { path = "../migration" }
|
migration = { path = "../migration" }
|
||||||
|
ciborium = "0.2.2"
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
config = "0.14.0"
|
config = "0.14.0"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
|
itertools = "0.12.1"
|
||||||
reqwest = { version = "0.12.4", features = ["json", "rustls-tls"], default-features = false }
|
reqwest = { version = "0.12.4", features = ["json", "rustls-tls"], default-features = false }
|
||||||
rumqttc = "0.24.0"
|
rumqttc = "0.24.0"
|
||||||
sea-orm = { workspace = true, features = [ "with-time", "sqlx-sqlite", "sqlx-postgres", "sqlx-mysql", "runtime-tokio-rustls", "macros" ] }
|
sea-orm = { workspace = true, features = [ "with-time", "sqlx-sqlite", "sqlx-postgres", "sqlx-mysql", "runtime-tokio-rustls", "macros" ] }
|
||||||
|
77
app/src/data/alert.rs
Normal file
77
app/src/data/alert.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use std::io::{self, Cursor};
|
||||||
|
|
||||||
|
use ciborium::into_writer;
|
||||||
|
use itertools::izip;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use time::PrimitiveDateTime;
|
||||||
|
|
||||||
|
use crate::json::{self};
|
||||||
|
|
||||||
|
use super::{area::Area, image::Image, link::Link, text::Text};
|
||||||
|
|
||||||
|
pub type Cbor = Vec<u8>;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Alert {
|
||||||
|
pub id: String,
|
||||||
|
title: Text,
|
||||||
|
description: Text,
|
||||||
|
nation_wide: bool,
|
||||||
|
instructions: Vec<Text>,
|
||||||
|
sender: String,
|
||||||
|
publisher: Option<String>,
|
||||||
|
links: Vec<Link>,
|
||||||
|
contact: Text,
|
||||||
|
event: String,
|
||||||
|
all_clear: bool,
|
||||||
|
severity: String,
|
||||||
|
publish_date: PrimitiveDateTime,
|
||||||
|
areas: Vec<Area>,
|
||||||
|
images: Vec<Image>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::alert::Alert> for Alert {
|
||||||
|
fn from(value: json::alert::Alert) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.identifier.clone(),
|
||||||
|
title: value.title.into(),
|
||||||
|
description: value.description.into(),
|
||||||
|
nation_wide: value.nation_wide,
|
||||||
|
instructions: value.instructions.into_iter().map(|x| x.into()).collect(),
|
||||||
|
sender: value.sender,
|
||||||
|
publisher: value.publisher_name,
|
||||||
|
links: value.links.into_iter().map(|x| x.into()).collect(),
|
||||||
|
contact: value.contact.into(),
|
||||||
|
event: value.event,
|
||||||
|
all_clear: value.all_clear,
|
||||||
|
severity: value.severity,
|
||||||
|
publish_date: value.publish_date,
|
||||||
|
areas: value.areas.into_iter().map(|x| x.into()).collect(),
|
||||||
|
images: izip!(
|
||||||
|
&value.images,
|
||||||
|
&value.image_titles,
|
||||||
|
&value.image_descriptions
|
||||||
|
)
|
||||||
|
.map(|(img, title, desc)| Image {
|
||||||
|
uri: img.uri.clone(),
|
||||||
|
digest: img.digest.clone(),
|
||||||
|
title: title.title.clone().into(),
|
||||||
|
alt_text: title.alt_text.clone(),
|
||||||
|
description: desc.description.clone().into(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Alert> for Cbor {
|
||||||
|
type Error = ciborium::ser::Error<io::Error>;
|
||||||
|
|
||||||
|
fn try_from(value: Alert) -> Result<Self, Self::Error> {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let writer = Cursor::new(&mut buffer);
|
||||||
|
into_writer(&value, writer)?;
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
}
|
24
app/src/data/area.rs
Normal file
24
app/src/data/area.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::json;
|
||||||
|
|
||||||
|
use super::{circle::Circle, polygon::Polygon, text::Text};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Area {
|
||||||
|
pub description: Text,
|
||||||
|
pub regions: Vec<String>,
|
||||||
|
pub polygons: Vec<Polygon>,
|
||||||
|
pub circles: Vec<Circle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::area::Area> for Area {
|
||||||
|
fn from(value: json::area::Area) -> Self {
|
||||||
|
Self {
|
||||||
|
description: value.description.into(),
|
||||||
|
regions: value.regions.into_iter().map(|x| x.region).collect(),
|
||||||
|
polygons: value.polygons.into_iter().map(|x| x.into()).collect(),
|
||||||
|
circles: value.circles.into_iter().map(|x| x.into()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
app/src/data/circle.rs
Normal file
20
app/src/data/circle.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::json;
|
||||||
|
|
||||||
|
use super::coordinate::Coordinate;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Circle {
|
||||||
|
pub center_position: Coordinate,
|
||||||
|
radius: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::circle::Circle> for Circle {
|
||||||
|
fn from(value: json::circle::Circle) -> Self {
|
||||||
|
Self {
|
||||||
|
center_position: value.center_position.into(),
|
||||||
|
radius: value.radius,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
app/src/data/coordinate.rs
Normal file
9
app/src/data/coordinate.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use crate::json;
|
||||||
|
|
||||||
|
pub type Coordinate = (String, String);
|
||||||
|
|
||||||
|
impl From<json::coordinate::Coordinate> for Coordinate {
|
||||||
|
fn from(value: json::coordinate::Coordinate) -> Self {
|
||||||
|
(value.zero, value.one)
|
||||||
|
}
|
||||||
|
}
|
12
app/src/data/image.rs
Normal file
12
app/src/data/image.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::text::Text;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Image {
|
||||||
|
pub uri: String,
|
||||||
|
pub digest: String,
|
||||||
|
pub title: Text,
|
||||||
|
pub alt_text: String,
|
||||||
|
pub description: Text,
|
||||||
|
}
|
18
app/src/data/link.rs
Normal file
18
app/src/data/link.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::json;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Link {
|
||||||
|
pub href: String,
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::link::Link> for Link {
|
||||||
|
fn from(value: json::link::Link) -> Self {
|
||||||
|
Self {
|
||||||
|
href: value.href,
|
||||||
|
text: value.text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
app/src/data/polygon.rs
Normal file
18
app/src/data/polygon.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::json;
|
||||||
|
|
||||||
|
use super::coordinate::Coordinate;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Polygon {
|
||||||
|
pub coordinates: Vec<Coordinate>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::polygon::Polygon> for Polygon {
|
||||||
|
fn from(value: json::polygon::Polygon) -> Self {
|
||||||
|
Self {
|
||||||
|
coordinates: value.coordinates.into_iter().map(|x| x.into()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
app/src/data/text.rs
Normal file
45
app/src/data/text.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::json::{self, contact::Contact, description::Description, title::Title};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Text {
|
||||||
|
pub origin: Option<String>,
|
||||||
|
pub translated: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Title> for Text {
|
||||||
|
fn from(value: Title) -> Self {
|
||||||
|
Self {
|
||||||
|
origin: value.title_gtrans_origin,
|
||||||
|
translated: value.title,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Description> for Text {
|
||||||
|
fn from(value: Description) -> Self {
|
||||||
|
Self {
|
||||||
|
origin: value.description_gtrans_origin,
|
||||||
|
translated: value.description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<json::text::Text> for Text {
|
||||||
|
fn from(value: json::text::Text) -> Self {
|
||||||
|
Self {
|
||||||
|
origin: value.text_origin,
|
||||||
|
translated: value.text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Contact> for Text {
|
||||||
|
fn from(value: Contact) -> Self {
|
||||||
|
Self {
|
||||||
|
origin: value.contact_origin,
|
||||||
|
translated: value.contact,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use data::alert::Cbor;
|
||||||
use datastore::rdbms::Db;
|
use datastore::rdbms::Db;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use futures::{stream, StreamExt};
|
use futures::{stream, StreamExt};
|
||||||
@ -12,6 +13,16 @@ use crate::json::alert::Alert;
|
|||||||
pub mod alert_swiss;
|
pub mod alert_swiss;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod data {
|
||||||
|
pub mod alert;
|
||||||
|
pub mod area;
|
||||||
|
pub mod circle;
|
||||||
|
pub mod coordinate;
|
||||||
|
pub mod image;
|
||||||
|
pub mod link;
|
||||||
|
pub mod polygon;
|
||||||
|
pub mod text;
|
||||||
|
}
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod datastore {
|
pub mod datastore {
|
||||||
pub mod rdbms;
|
pub mod rdbms;
|
||||||
@ -80,8 +91,18 @@ pub async fn run(config: Config) -> Result<(), Error> {
|
|||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
|
|
||||||
let new_alerts = handle_alerts(db).await?;
|
let new_alerts = handle_alerts(db).await?;
|
||||||
if let Err(e) = mqtt.publish("chello".as_bytes()).await {
|
stream::iter(new_alerts)
|
||||||
|
.for_each(|alert| async {
|
||||||
|
let alert: data::alert::Alert = alert.into();
|
||||||
|
match <Cbor as TryFrom<data::alert::Alert>>::try_from(alert) {
|
||||||
|
Ok(cbor) => {
|
||||||
|
if let Err(e) = mqtt.publish(&cbor).await {
|
||||||
error!("failed pusblishing to mqtt: {e:?}")
|
error!("failed pusblishing to mqtt: {e:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(e) => error!("failed to serialize to cbor: {e:?}"),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user