Fixed docker issue temporarily
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use futures_util::try_join;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{Postgres, QueryBuilder};
|
||||
use crate::airports::{
|
||||
@@ -194,7 +195,7 @@ impl From<AirportRow> for Airport {
|
||||
}
|
||||
|
||||
impl Airport {
|
||||
pub async fn select(icao: &str, metar: bool) -> Option<Self> {
|
||||
pub async fn select(client: &Client, icao: &str, metar: bool) -> Option<Self> {
|
||||
let pool = db::pool();
|
||||
|
||||
let airport_fut = async {
|
||||
@@ -206,7 +207,7 @@ impl Airport {
|
||||
|
||||
let metar_fut = async {
|
||||
if metar {
|
||||
match Metar::find_all(&vec![icao.to_string()]).await {
|
||||
match Metar::find_all(client, &vec![icao.to_string()], &false).await {
|
||||
Ok(m) => Some(m.into_iter().nth(0)),
|
||||
Err(err) => {
|
||||
log::error!("{}", err);
|
||||
@@ -269,7 +270,7 @@ impl Airport {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn select_all(query: &AirportQuery) -> ApiResult<Vec<Self>> {
|
||||
pub async fn select_all(client: &Client, query: &AirportQuery) -> ApiResult<Vec<Self>> {
|
||||
let pool = db::pool();
|
||||
|
||||
let mut builder = QueryBuilder::<Postgres>::new("SELECT * FROM ");
|
||||
@@ -337,7 +338,7 @@ impl Airport {
|
||||
let runway_future = Runway::select_all_map(icaos.clone());
|
||||
let frequency_future = Frequency::select_all_map(icaos.clone());
|
||||
let metar_future = if query.metars.unwrap_or(false) {
|
||||
Some(Metar::find_all(&icaos))
|
||||
Some(Metar::find_all(client, &icaos, &false))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
airports::Airport,
|
||||
db::Paged,
|
||||
auth::{Auth, verify_role},
|
||||
AppState,
|
||||
};
|
||||
use actix_multipart::Multipart;
|
||||
use actix_web::{delete, get, post, put, web, HttpResponse, HttpRequest, ResponseError};
|
||||
@@ -53,7 +54,7 @@ async fn import_airports(mut payload: Multipart, auth: Auth) -> HttpResponse {
|
||||
}
|
||||
|
||||
#[get("")]
|
||||
async fn get_airports(req: HttpRequest) -> HttpResponse {
|
||||
async fn get_airports(data: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
|
||||
let mut query = match web::Query::<AirportQuery>::from_query(req.query_string()) {
|
||||
Ok(q) => q.into_inner(),
|
||||
Err(err) => {
|
||||
@@ -71,7 +72,8 @@ async fn get_airports(req: HttpRequest) -> HttpResponse {
|
||||
query.limit = Some(limit);
|
||||
query.page = Some(page);
|
||||
|
||||
match Airport::select_all(&query).await {
|
||||
let client = &data.client;
|
||||
match Airport::select_all(client, &query).await {
|
||||
Ok(airports) => HttpResponse::Ok().json(Paged {
|
||||
data: airports,
|
||||
page,
|
||||
@@ -86,7 +88,11 @@ async fn get_airports(req: HttpRequest) -> HttpResponse {
|
||||
}
|
||||
|
||||
#[get("/{icao}")]
|
||||
async fn get_airport(icao: web::Path<String>, req: HttpRequest) -> HttpResponse {
|
||||
async fn get_airport(
|
||||
data: web::Data<AppState>,
|
||||
icao: web::Path<String>,
|
||||
req: HttpRequest,
|
||||
) -> HttpResponse {
|
||||
let metar = match web::Query::<AirportQuery>::from_query(req.query_string()) {
|
||||
Ok(q) => q.metars.unwrap_or_else(|| false),
|
||||
Err(err) => {
|
||||
@@ -95,7 +101,8 @@ async fn get_airport(icao: web::Path<String>, req: HttpRequest) -> HttpResponse
|
||||
}
|
||||
};
|
||||
|
||||
match Airport::select(&icao.into_inner(), metar).await {
|
||||
let client = &data.client;
|
||||
match Airport::select(client, &icao.into_inner(), metar).await {
|
||||
Some(airport) => HttpResponse::Ok().json(airport),
|
||||
None => HttpResponse::NotFound().finish(),
|
||||
}
|
||||
|
||||
@@ -97,7 +97,18 @@ impl From<std::env::VarError> for Error {
|
||||
|
||||
impl From<reqwest::Error> for Error {
|
||||
fn from(error: reqwest::Error) -> Self {
|
||||
Self::new(500, format!("Unknown reqwest error: {}", error))
|
||||
match error.status() {
|
||||
Some(status_code) => {
|
||||
if status_code.is_client_error() {
|
||||
Self::new(500, format!("Client reqwest error: {}", error))
|
||||
} else if status_code.is_server_error() {
|
||||
Self::new(500, format!("Server reqwest error: {}", error))
|
||||
} else {
|
||||
Self::new(500, format!("Unknown reqwest error: {:?}", error))
|
||||
}
|
||||
}
|
||||
_ => Self::new(500, format!("Unknown reqwest error: {:?}", error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::env;
|
||||
|
||||
use std::time::Duration;
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{App, HttpServer, middleware::Logger, web};
|
||||
use dotenv::from_filename;
|
||||
@@ -14,15 +14,17 @@ mod metars;
|
||||
mod scheduler;
|
||||
mod users;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct AppState {
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
initialize_environment()?;
|
||||
db::initialize().await?;
|
||||
// scheduler::update_airports();
|
||||
|
||||
let host = "0.0.0.0".to_string();
|
||||
let port = env::var("API_PORT").unwrap_or("5000".to_string());
|
||||
|
||||
// Initialize admin user
|
||||
let admin_email = env::var("ADMIN_EMAIL");
|
||||
let admin_password = env::var("ADMIN_PASSWORD");
|
||||
@@ -55,6 +57,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(10))
|
||||
.no_proxy()
|
||||
.danger_accept_invalid_certs(true)
|
||||
.build()
|
||||
.expect("Failed to create reqwest client");
|
||||
|
||||
let state = AppState { client };
|
||||
let host = env::var("API_HOST").unwrap_or("localhost".to_string());
|
||||
let port = env::var("API_PORT").unwrap_or("5000".to_string());
|
||||
|
||||
let server = match HttpServer::new(move || {
|
||||
let cors = Cors::default()
|
||||
.allow_any_origin()
|
||||
@@ -62,18 +75,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.allow_any_header()
|
||||
.supports_credentials()
|
||||
.max_age(3600);
|
||||
App::new().wrap(cors).wrap(Logger::default()).service(
|
||||
web::scope("api")
|
||||
.configure(airports::init_routes)
|
||||
.configure(metars::init_routes)
|
||||
.configure(auth::init_routes)
|
||||
.configure(users::init_routes),
|
||||
)
|
||||
App::new()
|
||||
.wrap(cors)
|
||||
.wrap(Logger::default())
|
||||
.app_data(web::Data::new(state.clone()))
|
||||
.service(
|
||||
web::scope("api")
|
||||
.configure(airports::init_routes)
|
||||
.configure(metars::init_routes)
|
||||
.configure(auth::init_routes)
|
||||
.configure(users::init_routes),
|
||||
)
|
||||
})
|
||||
.bind(format!("{}:{}", host, port))
|
||||
{
|
||||
Ok(b) => {
|
||||
log::info!("Binding server to {}:{}", host, port);
|
||||
log::info!("Server bound to {}:{}", host, port);
|
||||
b
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::{error::ApiResult, db};
|
||||
use chrono::{DateTime, Datelike, Utc};
|
||||
use std::collections::HashSet;
|
||||
use redis::{AsyncCommands, RedisResult};
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::db::redis_async_connection;
|
||||
|
||||
@@ -845,8 +846,8 @@ impl Metar {
|
||||
missing_metar_icaos
|
||||
}
|
||||
|
||||
async fn get_remote_metars(icaos: &[&str]) -> ApiResult<Vec<Metar>> {
|
||||
let gov_api_url = std::env::var("GOV_API_URL").expect("GOV_API_URL must be set");
|
||||
async fn get_remote_metars(client: &Client, icaos: &[&str]) -> ApiResult<Vec<Metar>> {
|
||||
let base_url = std::env::var("AVIATION_WEATHER_URL").expect("GOV_API_URL must be set");
|
||||
// Query the remote API for the missing METAR data 10 at a time
|
||||
let icao_chunks = icaos
|
||||
.chunks(10)
|
||||
@@ -854,14 +855,14 @@ impl Metar {
|
||||
.collect::<Vec<String>>();
|
||||
let mut metars: Vec<Metar> = vec![];
|
||||
for icao_chunk in icao_chunks {
|
||||
let url = format!("{}/metar.php?ids={}", gov_api_url, icao_chunk);
|
||||
let mut m = match reqwest::get(url).await {
|
||||
let url = format!("{}/metar?ids={}&order=id", base_url, icao_chunk);
|
||||
let mut m = match client.get(url).send().await {
|
||||
Ok(r) => {
|
||||
// Check if the status code is 200
|
||||
if r.status() != 200 {
|
||||
return Err(Error::new(
|
||||
500,
|
||||
format!("Unable to get METAR request: {}", r.status()),
|
||||
format!("Request returned status {}", r.status()),
|
||||
));
|
||||
}
|
||||
match r.text().await {
|
||||
@@ -876,20 +877,10 @@ impl Metar {
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(Error::new(
|
||||
500,
|
||||
format!("Unable to parse METAR request: {}", err),
|
||||
))
|
||||
}
|
||||
Err(err) => return Err(Error::new(500, format!("METAR parse failed: {}", err))),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(Error::new(
|
||||
500,
|
||||
format!("Unable to get METAR request: {}", err),
|
||||
))
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
metars.append(&mut m);
|
||||
}
|
||||
@@ -911,7 +902,11 @@ impl Metar {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn find_all(icao_list: &Vec<String>) -> ApiResult<Vec<Self>> {
|
||||
pub async fn find_all(
|
||||
client: &Client,
|
||||
icao_list: &Vec<String>,
|
||||
force: &bool,
|
||||
) -> ApiResult<Vec<Self>> {
|
||||
if icao_list.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
@@ -937,17 +932,21 @@ impl Metar {
|
||||
if !missing_icao_list.is_empty() {
|
||||
let mut updated_missing_icao_list: Vec<&str> = Vec::new();
|
||||
for icao in &missing_icao_list {
|
||||
let result: RedisResult<Option<bool>> = conn.get(icao).await;
|
||||
match result {
|
||||
Ok(Some(value)) => {
|
||||
if value {
|
||||
if *force {
|
||||
updated_missing_icao_list.push(icao);
|
||||
} else {
|
||||
let result: RedisResult<Option<bool>> = conn.get(icao).await;
|
||||
match result {
|
||||
Ok(Some(value)) => {
|
||||
if value {
|
||||
updated_missing_icao_list.push(icao);
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
updated_missing_icao_list.push(icao);
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
}
|
||||
Ok(None) => {
|
||||
updated_missing_icao_list.push(icao);
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
}
|
||||
}
|
||||
if !updated_missing_icao_list.is_empty() {
|
||||
@@ -955,7 +954,7 @@ impl Metar {
|
||||
"Retrieving missing METAR data for {:?}",
|
||||
updated_missing_icao_list
|
||||
);
|
||||
let mut missing_icao_list = Self::get_remote_metars(&updated_missing_icao_list)
|
||||
let mut missing_icao_list = Self::get_remote_metars(client, &updated_missing_icao_list)
|
||||
.await
|
||||
.unwrap_or_else(|err| {
|
||||
log::warn!("Unable to get remote METAR data; {}", err);
|
||||
|
||||
@@ -2,14 +2,16 @@ use crate::metars::Metar;
|
||||
use actix_web::{get, web, HttpResponse, HttpRequest};
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::AppState;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct FindAllParameters {
|
||||
icaos: Option<String>,
|
||||
force: Option<bool>,
|
||||
}
|
||||
|
||||
#[get("metars")]
|
||||
async fn find_all(req: HttpRequest) -> HttpResponse {
|
||||
async fn find_all(data: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
|
||||
let parameters = web::Query::<FindAllParameters>::from_query(req.query_string()).unwrap();
|
||||
let icao_option = ¶meters.icaos;
|
||||
let icao_string = match icao_option {
|
||||
@@ -17,8 +19,10 @@ async fn find_all(req: HttpRequest) -> HttpResponse {
|
||||
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
||||
};
|
||||
let icaos: Vec<String> = icao_string.split(',').map(|s| s.to_string()).collect();
|
||||
let force = ¶meters.force.unwrap_or(false);
|
||||
|
||||
let metars = match Metar::find_all(&icaos).await {
|
||||
let client = &data.client;
|
||||
let metars = match Metar::find_all(client, &icaos, force).await {
|
||||
Ok(a) => a,
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
|
||||
Reference in New Issue
Block a user