Tweaking find all metars
This commit is contained in:
2
.env
2
.env
@@ -28,7 +28,7 @@ MINIO_BROWSER_REDIRECT_URL=${NGINX_PROTOCOL}://${NGINX_HOST}:${NGINX_HTTP_PORT}/
|
|||||||
|
|
||||||
UI_PORT=3000
|
UI_PORT=3000
|
||||||
API_PORT=5000
|
API_PORT=5000
|
||||||
API_METAR_TIME_OFFSET=3000
|
API_METAR_TIME_OFFSET=1800
|
||||||
|
|
||||||
SSL_CA_NAME=ca
|
SSL_CA_NAME=ca
|
||||||
SSL_CA_PATH=../ssl/${SSL_CA_NAME}.pem
|
SSL_CA_PATH=../ssl/${SSL_CA_NAME}.pem
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ impl Airport {
|
|||||||
|
|
||||||
let metar_fut = async {
|
let metar_fut = async {
|
||||||
if metar {
|
if metar {
|
||||||
match Metar::find_all(client, &vec![icao.to_string()], &false).await {
|
match Metar::find_all_distinct(client, &vec![icao.to_string()]).await {
|
||||||
Ok(m) => Some(m.into_iter().nth(0)),
|
Ok(m) => Some(m.into_iter().nth(0)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("{}", err);
|
log::error!("{}", err);
|
||||||
@@ -345,7 +345,7 @@ impl Airport {
|
|||||||
let runway_future = Runway::select_all_map(icaos.clone());
|
let runway_future = Runway::select_all_map(icaos.clone());
|
||||||
let frequency_future = Frequency::select_all_map(icaos.clone());
|
let frequency_future = Frequency::select_all_map(icaos.clone());
|
||||||
let metar_future = if query.metars.unwrap_or(false) {
|
let metar_future = if query.metars.unwrap_or(false) {
|
||||||
Some(Metar::find_all(client, &icaos, &false))
|
Some(Metar::find_all_distinct(client, &icaos))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,20 +3,31 @@ use redis::{AsyncCommands, RedisResult};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::db::redis_async_connection;
|
use crate::db::redis_async_connection;
|
||||||
use crate::error::ApiResult;
|
use crate::error::ApiResult;
|
||||||
|
use crate::metars::Metar;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct MetarCheck {
|
pub struct MetarCheck {
|
||||||
pub icao: String,
|
pub icao: String,
|
||||||
pub status: bool,
|
pub status: bool,
|
||||||
pub updated_at: DateTime<Utc>,
|
pub updated_at: DateTime<Utc>,
|
||||||
|
pub last_metar: Option<Metar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetarCheck {
|
impl MetarCheck {
|
||||||
pub fn new(icao: String, status: bool) -> Self {
|
pub async fn new(icao: String, status: bool) -> Self {
|
||||||
Self {
|
match Self::get(&icao).await {
|
||||||
|
Some(c) => Self {
|
||||||
icao,
|
icao,
|
||||||
status,
|
status,
|
||||||
updated_at: Utc::now(),
|
updated_at: Utc::now(),
|
||||||
|
last_metar: c.last_metar,
|
||||||
|
},
|
||||||
|
None => Self {
|
||||||
|
icao,
|
||||||
|
status,
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
last_metar: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use crate::metars::MetarCheck;
|
|||||||
|
|
||||||
const TABLE_NAME: &str = "metars";
|
const TABLE_NAME: &str = "metars";
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Metar {
|
pub struct Metar {
|
||||||
pub icao: String,
|
pub icao: String,
|
||||||
pub raw_text: String,
|
pub raw_text: String,
|
||||||
@@ -60,7 +60,7 @@ pub struct Metar {
|
|||||||
pub density_altitude: Option<f64>,
|
pub density_altitude: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ReportModifier {
|
pub enum ReportModifier {
|
||||||
#[serde(rename = "AUTO")]
|
#[serde(rename = "AUTO")]
|
||||||
Auto,
|
Auto,
|
||||||
@@ -88,7 +88,7 @@ impl Display for ReportModifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RunwayVisualRange {
|
pub struct RunwayVisualRange {
|
||||||
pub runway: String,
|
pub runway: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -110,7 +110,7 @@ impl Default for RunwayVisualRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum AutomatedStationType {
|
pub enum AutomatedStationType {
|
||||||
#[serde(rename = "AO1")]
|
#[serde(rename = "AO1")]
|
||||||
WithoutPrecipitationDiscriminator,
|
WithoutPrecipitationDiscriminator,
|
||||||
@@ -141,7 +141,7 @@ impl Display for AutomatedStationType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Remarks {
|
pub struct Remarks {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub peak_wind: Option<PeakWind>,
|
pub peak_wind: Option<PeakWind>,
|
||||||
@@ -165,7 +165,7 @@ pub struct Remarks {
|
|||||||
pub sky_condition_at_secondary_location_not_available: Option<String>,
|
pub sky_condition_at_secondary_location_not_available: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PeakWind {
|
pub struct PeakWind {
|
||||||
pub degrees: i32,
|
pub degrees: i32,
|
||||||
pub speed: i32,
|
pub speed: i32,
|
||||||
@@ -190,7 +190,7 @@ impl Default for Remarks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SkyCondition {
|
pub struct SkyCondition {
|
||||||
pub sky_cover: String,
|
pub sky_cover: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -209,7 +209,7 @@ impl Default for SkyCondition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum FlightCategory {
|
pub enum FlightCategory {
|
||||||
VFR,
|
VFR,
|
||||||
MVFR,
|
MVFR,
|
||||||
@@ -993,10 +993,9 @@ impl Metar {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_all(
|
pub async fn find_all_distinct(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
icao_list: &Vec<String>,
|
icao_list: &Vec<String>
|
||||||
_force: &bool,
|
|
||||||
) -> ApiResult<Vec<Self>> {
|
) -> ApiResult<Vec<Self>> {
|
||||||
if icao_list.is_empty() {
|
if icao_list.is_empty() {
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
@@ -1017,9 +1016,9 @@ impl Metar {
|
|||||||
|
|
||||||
let current_time = Utc::now().timestamp();
|
let current_time = Utc::now().timestamp();
|
||||||
let time_offset = env::var("API_METAR_TIME_OFFSET")
|
let time_offset = env::var("API_METAR_TIME_OFFSET")
|
||||||
.unwrap_or("3000".to_string())
|
.unwrap_or("1800".to_string())
|
||||||
.parse::<i64>()
|
.parse::<i64>()
|
||||||
.unwrap_or(3000);
|
.unwrap_or(1800);
|
||||||
let short_time_offset: i64 = 300;
|
let short_time_offset: i64 = 300;
|
||||||
|
|
||||||
// Setup metars and missing metar structures
|
// Setup metars and missing metar structures
|
||||||
@@ -1042,8 +1041,8 @@ impl Metar {
|
|||||||
};
|
};
|
||||||
// If the metar was cached more than short_time_offset minutes ago, refresh it
|
// If the metar was cached more than short_time_offset minutes ago, refresh it
|
||||||
if refresh_seconds >= short_time_offset {
|
if refresh_seconds >= short_time_offset {
|
||||||
log::trace!("{} METAR data is outdated, refreshing now", &icao);
|
log::trace!("{} METAR data is outdated, marked for refresh", &icao);
|
||||||
missing_metar_icaos.push(icao);
|
missing_metar_icaos.push(icao.clone());
|
||||||
}
|
}
|
||||||
// Otherwise return outdated data and wait
|
// Otherwise return outdated data and wait
|
||||||
else {
|
else {
|
||||||
@@ -1058,7 +1057,7 @@ impl Metar {
|
|||||||
// Otherwise add the metar to the vector
|
// Otherwise add the metar to the vector
|
||||||
else {
|
else {
|
||||||
found_metar_icaos.insert(icao.clone());
|
found_metar_icaos.insert(icao.clone());
|
||||||
let metar_check = MetarCheck::new(icao, true);
|
let metar_check = MetarCheck::new(icao, true).await;
|
||||||
metar_check.insert(time_offset as u64).await?;
|
metar_check.insert(time_offset as u64).await?;
|
||||||
metars.push(Metar::from_db(metar_row)?);
|
metars.push(Metar::from_db(metar_row)?);
|
||||||
}
|
}
|
||||||
@@ -1092,21 +1091,29 @@ impl Metar {
|
|||||||
|
|
||||||
if remote_metars.len() > 0 {
|
if remote_metars.len() > 0 {
|
||||||
// Insert missing METARs
|
// Insert missing METARs
|
||||||
for remote_metar in &remote_metars {
|
for remote_metar in remote_metars.clone() {
|
||||||
found_metar_icaos.insert(remote_metar.icao.to_string());
|
|
||||||
let metar_check = MetarCheck::new(remote_metar.icao.clone(), true);
|
|
||||||
metar_check.insert(time_offset as u64).await?;
|
|
||||||
remote_metar.insert().await?;
|
remote_metar.insert().await?;
|
||||||
|
found_metar_icaos.insert(remote_metar.icao.to_string());
|
||||||
|
let mut metar_check = MetarCheck::new(remote_metar.icao.clone(), true).await;
|
||||||
|
metar_check.last_metar = Some(remote_metar);
|
||||||
|
metar_check.insert(time_offset as u64).await?;
|
||||||
}
|
}
|
||||||
metars.append(&mut remote_metars)
|
metars.append(&mut remote_metars);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update still missing metars
|
// Update still missing metars
|
||||||
let mut still_missing_metar_icaos: Vec<String> = vec![];
|
// let mut still_missing_metar_icaos: Vec<String> = vec![];
|
||||||
for difference in found_metar_icaos.symmetric_difference(&requested_icaos) {
|
for difference in found_metar_icaos.symmetric_difference(&requested_icaos) {
|
||||||
still_missing_metar_icaos.push(difference.to_string());
|
// still_missing_metar_icaos.push(difference.to_string());
|
||||||
let metar_check = MetarCheck::new(difference.to_string(), false);
|
let metar_check = MetarCheck::new(difference.to_string(), false).await;
|
||||||
metar_check.insert(short_time_offset as u64).await?
|
metar_check.insert(short_time_offset as u64).await?;
|
||||||
|
// Only add cached metar data if it's less than 4 hours old
|
||||||
|
if let Some(last_metar) = metar_check.last_metar {
|
||||||
|
let four_hours_ago = Utc::now() - chrono::Duration::hours(4);
|
||||||
|
if last_metar.observation_time < four_hours_ago {
|
||||||
|
metars.push(last_metar);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if !still_missing_metar_icaos.is_empty() {
|
// if !still_missing_metar_icaos.is_empty() {
|
||||||
// log::trace!("Still missing METAR data from {:?}", still_missing_metar_icaos);
|
// log::trace!("Still missing METAR data from {:?}", still_missing_metar_icaos);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::AppState;
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct FindAllParameters {
|
struct FindAllParameters {
|
||||||
icaos: Option<String>,
|
icaos: Option<String>,
|
||||||
force: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("metars")]
|
#[get("metars")]
|
||||||
@@ -19,10 +18,9 @@ async fn find_all(data: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
|
|||||||
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
||||||
};
|
};
|
||||||
let icaos: Vec<String> = icao_string.split(',').map(|s| s.to_string()).collect();
|
let icaos: Vec<String> = icao_string.split(',').map(|s| s.to_string()).collect();
|
||||||
let force = ¶meters.force.unwrap_or(false);
|
|
||||||
|
|
||||||
let client = &data.client;
|
let client = &data.client;
|
||||||
let metars = match Metar::find_all(client, &icaos, force).await {
|
let metars = match Metar::find_all_distinct(client, &icaos).await {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
|
|||||||
Reference in New Issue
Block a user