Cleanup
This commit is contained in:
@@ -8,9 +8,9 @@ use rand_chacha::ChaCha20Rng;
|
||||
|
||||
mod auth;
|
||||
mod email_token;
|
||||
mod model;
|
||||
mod routes;
|
||||
mod session;
|
||||
mod model;
|
||||
|
||||
pub use auth::*;
|
||||
pub use routes::init_routes;
|
||||
|
||||
@@ -80,53 +80,53 @@ impl Default for AirportQuery {
|
||||
}
|
||||
}
|
||||
|
||||
impl AirportQuery {
|
||||
pub fn builder() -> AirportQueryBuilder {
|
||||
AirportQueryBuilder::new()
|
||||
}
|
||||
}
|
||||
// impl AirportQuery {
|
||||
// pub fn builder() -> AirportQueryBuilder {
|
||||
// AirportQueryBuilder::new()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct AirportQueryBuilder {
|
||||
inner: AirportQuery,
|
||||
}
|
||||
|
||||
impl AirportQueryBuilder {
|
||||
/// start the builder
|
||||
pub fn new() -> Self {
|
||||
AirportQueryBuilder {
|
||||
inner: AirportQuery::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn page(mut self, page: u32) -> Self {
|
||||
self.inner.page = Some(page);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn limit(mut self, limit: u32) -> Self {
|
||||
self.inner.limit = Some(limit);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn icaos<T: Into<String>>(mut self, v: T) -> Self {
|
||||
self.inner.icaos = Some(v.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn iatas<T: Into<String>>(mut self, v: T) -> Self {
|
||||
self.inner.iatas = Some(v.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn metars(mut self, v: bool) -> Self {
|
||||
self.inner.metars = Some(v);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> AirportQuery {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
// pub struct AirportQueryBuilder {
|
||||
// inner: AirportQuery,
|
||||
// }
|
||||
//
|
||||
// impl AirportQueryBuilder {
|
||||
// /// start the builder
|
||||
// pub fn new() -> Self {
|
||||
// AirportQueryBuilder {
|
||||
// inner: AirportQuery::default(),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn page(mut self, page: u32) -> Self {
|
||||
// self.inner.page = Some(page);
|
||||
// self
|
||||
// }
|
||||
//
|
||||
// pub fn limit(mut self, limit: u32) -> Self {
|
||||
// self.inner.limit = Some(limit);
|
||||
// self
|
||||
// }
|
||||
//
|
||||
// pub fn icaos<T: Into<String>>(mut self, v: T) -> Self {
|
||||
// self.inner.icaos = Some(v.into());
|
||||
// self
|
||||
// }
|
||||
//
|
||||
// pub fn iatas<T: Into<String>>(mut self, v: T) -> Self {
|
||||
// self.inner.iatas = Some(v.into());
|
||||
// self
|
||||
// }
|
||||
//
|
||||
// pub fn metars(mut self, v: bool) -> Self {
|
||||
// self.inner.metars = Some(v);
|
||||
// self
|
||||
// }
|
||||
//
|
||||
// pub fn build(self) -> AirportQuery {
|
||||
// self.inner
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct Bounds {
|
||||
|
||||
@@ -83,7 +83,8 @@ impl HttpClient {
|
||||
if response.status() != 200 {
|
||||
return Err(Error::new(
|
||||
response.status().as_u16(),
|
||||
format!("Request returned status {}", response.status())));
|
||||
format!("Request returned status {}", response.status()),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
|
||||
@@ -35,7 +35,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Arc::new(HttpClient::default()?);
|
||||
|
||||
let scheduler_client = client.clone();
|
||||
scheduler::update_metars(scheduler_client, 600);
|
||||
let interval = env::var("METAR_INTERVAL")
|
||||
.unwrap_or("300".to_string())
|
||||
.parse::<u64>()
|
||||
.unwrap_or(300);
|
||||
scheduler::update_metars(scheduler_client, interval);
|
||||
|
||||
// Initialize admin user
|
||||
let admin_username = env::var("ADMIN_USERNAME");
|
||||
|
||||
@@ -4,6 +4,8 @@ use crate::http_client::HttpClient;
|
||||
use crate::metars::MetarCheck;
|
||||
use crate::{db, error::ApiResult};
|
||||
use chrono::{DateTime, Datelike, NaiveDate, Utc};
|
||||
use flate2::read::GzDecoder;
|
||||
use reqwest::header::ETAG;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
@@ -11,8 +13,6 @@ use std::fmt::Display;
|
||||
use std::io::{Cursor, Read};
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
use flate2::read::GzDecoder;
|
||||
use reqwest::header::ETAG;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
static TIME_OFFSET: OnceLock<i64> = OnceLock::new();
|
||||
@@ -921,12 +921,17 @@ impl Metar {
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let candidate_date = match candidate_date.and_hms_opt(observation_hour, observation_minute, 0) {
|
||||
let candidate_date = match candidate_date.and_hms_opt(observation_hour, observation_minute, 0) {
|
||||
Some(date) => date,
|
||||
None => return Err(Error::new(
|
||||
500,
|
||||
format!("Invalid time for time '{}': hour {}, minute {}",
|
||||
observation_time, observation_hour, observation_minute)))
|
||||
None => {
|
||||
return Err(Error::new(
|
||||
500,
|
||||
format!(
|
||||
"Invalid time for time '{}': hour {}, minute {}",
|
||||
observation_time, observation_hour, observation_minute
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let obs_datetime = if candidate_date > current_time {
|
||||
@@ -956,9 +961,11 @@ impl Metar {
|
||||
Ok(obs_datetime.format("%Y-%m-%dT%H:%M:00Z").to_string())
|
||||
}
|
||||
|
||||
pub async fn get_cached_remote_metars(client: &HttpClient, etag: Option<String>) -> ApiResult<(Vec<Self>, String)> {
|
||||
let base_url = env::var("AVIATION_WEATHER_URL")
|
||||
.expect("AVIATION_WEATHER_URL must be set");
|
||||
pub async fn get_cached_remote_metars(
|
||||
client: &HttpClient,
|
||||
etag: Option<String>,
|
||||
) -> ApiResult<(Vec<Self>, String)> {
|
||||
let base_url = env::var("AVIATION_WEATHER_URL").expect("AVIATION_WEATHER_URL must be set");
|
||||
let url = format!("{}/data/cache/metars.cache.csv.gz", base_url);
|
||||
|
||||
match client.get(&url, etag.clone()).await {
|
||||
@@ -991,8 +998,8 @@ impl Metar {
|
||||
Some(etag) => Ok((output, etag)),
|
||||
None => match etag {
|
||||
Some(etag) => Ok((output, etag)),
|
||||
None => Ok((output, String::new()))
|
||||
}
|
||||
None => Ok((output, String::new())),
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err.into()),
|
||||
@@ -1000,8 +1007,7 @@ impl Metar {
|
||||
}
|
||||
|
||||
pub async fn get_remote_metars(client: &HttpClient, icaos: &Vec<String>) -> ApiResult<Vec<Self>> {
|
||||
let base_url = env::var("AVIATION_WEATHER_URL")
|
||||
.expect("AVIATION_WEATHER_URL must be set");
|
||||
let base_url = env::var("AVIATION_WEATHER_URL").expect("AVIATION_WEATHER_URL must be set");
|
||||
// Query the remote API for the missing METAR data 10 at a time
|
||||
let icao_chunks = icaos
|
||||
.chunks(10)
|
||||
@@ -1014,22 +1020,20 @@ impl Metar {
|
||||
base_url, icao_chunk
|
||||
);
|
||||
let mut m = match client.get(&url, None).await {
|
||||
Ok(r) => {
|
||||
match r.text().await {
|
||||
Ok(r) => {
|
||||
let metar_chunk = r
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter(|m| !m.trim().is_empty())
|
||||
.collect();
|
||||
match Self::parse_multiple(&metar_chunk) {
|
||||
Ok(m) => m,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
Ok(r) => match r.text().await {
|
||||
Ok(r) => {
|
||||
let metar_chunk = r
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter(|m| !m.trim().is_empty())
|
||||
.collect();
|
||||
match Self::parse_multiple(&metar_chunk) {
|
||||
Ok(m) => m,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
Err(err) => return Err(Error::new(500, format!("METAR parse failed: {}", err))),
|
||||
}
|
||||
}
|
||||
Err(err) => return Err(Error::new(500, format!("METAR parse failed: {}", err))),
|
||||
},
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
metars.append(&mut m);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::AppState;
|
||||
use crate::account::Auth;
|
||||
use crate::metars::Metar;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, put, web};
|
||||
use log::error;
|
||||
@@ -6,7 +7,6 @@ use serde::Deserialize;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
use utoipa_actix_web::scope;
|
||||
use utoipa_actix_web::service_config::ServiceConfig;
|
||||
use crate::account::Auth;
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema, IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
@@ -85,37 +85,10 @@ async fn refresh_metars(data: web::Data<AppState>, req: HttpRequest, _auth: Auth
|
||||
HttpResponse::Ok().json(metars)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "metar",
|
||||
responses(
|
||||
(status = 200, description = "Successful Response", body = Metar),
|
||||
(status = 404, description = "Not Found"),
|
||||
),
|
||||
)]
|
||||
#[get("/{icao}")]
|
||||
async fn find(icao: web::Path<String>) -> HttpResponse {
|
||||
let icao = vec![icao.to_uppercase()];
|
||||
let metar = match Metar::get_all_distinct(&icao).await {
|
||||
Ok(metars) => {
|
||||
if metars.len() == 1 {
|
||||
metars[0].clone()
|
||||
} else {
|
||||
return HttpResponse::NotFound().finish()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
return err.to_http_response();
|
||||
}
|
||||
};
|
||||
HttpResponse::Ok().json(metar)
|
||||
}
|
||||
|
||||
pub fn init_routes(config: &mut ServiceConfig) {
|
||||
config.service(
|
||||
scope::scope("/metars")
|
||||
.service(find_all)
|
||||
.service(refresh_metars)
|
||||
.service(find)
|
||||
.service(refresh_metars),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub fn update_metars(client: Arc<HttpClient>, seconds: u64) {
|
||||
// Run the update
|
||||
match Metar::update_metars(&client, etag.clone()).await {
|
||||
Ok(new_etag) => etag = Some(new_etag),
|
||||
Err(err) => log::error!("METAR update failed: {}", err)
|
||||
Err(err) => log::error!("METAR update failed: {}", err),
|
||||
}
|
||||
|
||||
let elapsed = start_monotonic.elapsed();
|
||||
|
||||
@@ -21,7 +21,10 @@ pub struct SystemInfo {
|
||||
async fn info() -> HttpResponse {
|
||||
let healthy = true;
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let info = SystemInfo { version: version.to_string(), healthy };
|
||||
let info = SystemInfo {
|
||||
version: version.to_string(),
|
||||
healthy,
|
||||
};
|
||||
|
||||
HttpResponse::Ok().json(info)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user