1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use chrono::prelude::*;
use reqwest::{blocking, header::*};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("reqwest error")]
Reqwest(#[from] reqwest::Error),
#[error("serde_json error")]
Serde(#[from] serde_json::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Alert {
#[serde(rename = "data")]
pub areas: Vec<String>,
#[serde(rename = "id", with = "date_format")]
pub date: DateTime<Utc>,
pub title: String,
}
impl Alert {
pub fn get() -> Result<Option<Self>> {
let client = blocking::Client::new();
let resp = client
.get("https://www.oref.org.il/WarningMessages/alert/alerts.json")
.header(REFERER, "https://www.oref.org.il/12481-en/Pakar.aspx")
.header("X-Requested-With", "XMLHttpRequest")
.header(
USER_AGENT,
"oref-red-alert https://github.com/ronthecookie/oref-red-alert",
)
.send()
.map_err(|e| Error::Reqwest(e))?
.text()
.map_err(|e| Error::Reqwest(e))?;
Ok(if resp.len() > 0 {
Some(serde_json::from_str(&resp).map_err(|e| Error::Serde(e))?)
} else {
None
})
}
}
mod date_format {
use chrono::{DateTime, TimeZone, Utc};
use serde::{self, Deserialize, Deserializer, Serializer};
pub fn serialize<S>(date: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let num = date.timestamp_millis();
serializer.serialize_i64(num)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let s = i64::deserialize(deserializer)?;
Ok(Utc.timestamp_millis(s))
}
}
mod test {
#[test]
fn basic_get() {
use super::Alert;
Alert::get().unwrap();
}
#[test]
fn readme_example() {
use super::Alert;
let alert = Alert::get().unwrap();
if alert.is_some() {
eprintln!("Affected cities: {}", alert.unwrap().areas.len())
} else {
eprintln!("There is no alert available");
}
}
#[test]
fn consistent_serde() {
use super::Alert;
use chrono::{TimeZone, Utc};
let title = String::new();
let now = Utc.timestamp_millis(1337);
let alert = Alert {
areas: vec![],
date: now,
title,
};
eprintln!("{:?}", serde_json::to_string(&alert));
let new = serde_json::from_str::<Alert>(&serde_json::to_string(&alert).unwrap()).unwrap();
assert!(alert == new);
}
}