This commit is contained in:
2024-09-03 11:40:09 -04:00
parent 32a0ecc1e6
commit cc74be72be
17 changed files with 47 additions and 62 deletions

View File

@@ -1,6 +1,6 @@
RUST_LOG=warn,service=debug
DATABASE_CONTAINER=aviation-service
DATABASE_CONTAINER=aviation-db
DATABASE_USER=aviation
DATABASE_PASSWORD=
@@ -21,7 +21,7 @@ SERVICE_HOST=localhost
SERVICE_PORT=5000
KEYS_DIR_PATH=
ACCESS_TOKEN_MAXAGE=5
ACCESS_TOKEN_MAXAGE=240
REFRESH_TOKEN_MAXAGE=1440
GOV_API_URL=https://aviationweather.gov/cgi-bin/data

View File

@@ -60,3 +60,5 @@ generate-keys: ## Generate RSA keys
@openssl genrsa -out ../keys/refresh_private_key.pem 4096
@openssl rsa -in ../keys/refresh_private_key.pem -pubout -outform PEM -out ../keys/refresh_public_key.pem
psql: ## Connect to the PSQL DB
@docker exec -it ${DATABASE_CONTAINER} psql -U ${DATABASE_USER}

View File

@@ -0,0 +1 @@
DROP TABLE airport_metar_cache;

View File

@@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS airport_metar_cache (
icao TEXT PRIMARY KEY NOT NULL,
has_metar BOOLEAN NOT NULL DEFAULT FALSE,
last_checked TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -45,10 +45,16 @@ pub struct Airport {
pub has_beacon: Option<bool>,
pub runways: Vec<Runway>,
pub frequencies: Vec<Frequency>,
pub has_metar: bool,
pub public: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AirportMetarCache {
pub icao: String,
pub has_metar: bool,
pub last_checked: chrono::NaiveDateTime,
}
impl Into<QueryAirport> for Airport {
fn into(self) -> QueryAirport {
return QueryAirport {

View File

@@ -13,7 +13,7 @@ use postgis_diesel::types::{Polygon, Point};
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct GetAllParameters {
struct AirportsQuery {
icaos: Option<String>,
name: Option<String>,
bounds: Option<String>,
@@ -26,7 +26,7 @@ struct GetAllParameters {
}
#[post("/import")]
async fn import(mut payload: Multipart, auth: JwtAuth) -> HttpResponse {
async fn import_airports(mut payload: Multipart, auth: JwtAuth) -> HttpResponse {
if let Err(err) = verify_role(&auth, "admin") {
return ResponseError::error_response(&err);
};
@@ -70,8 +70,8 @@ async fn import(mut payload: Multipart, auth: JwtAuth) -> HttpResponse {
}
#[get("")]
async fn get_all(req: HttpRequest) -> HttpResponse {
let params = web::Query::<GetAllParameters>::from_query(req.query_string()).unwrap();
async fn get_airports(req: HttpRequest) -> HttpResponse {
let params = web::Query::<AirportsQuery>::from_query(req.query_string()).unwrap();
let mut filters = QueryFilters::default();
filters.icaos = match &params.icaos {
Some(i) => Some(i.split(",").map(|s| s.to_string()).collect()),
@@ -180,7 +180,6 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
Ok(t) => t,
Err(_) => 0,
};
let pages = ((total as f64) / (if limit <= 0 { 1 } else { limit } as f64)).ceil() as i64;
match web::block(move || QueryAirport::get_all(&filters, limit, page))
.await
@@ -197,7 +196,6 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
meta: Some(Metadata {
page,
limit,
pages,
total,
}),
})
@@ -210,19 +208,11 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
}
#[get("/{icao}")]
async fn get(icao: web::Path<String>) -> HttpResponse {
async fn get_airport(icao: web::Path<String>) -> HttpResponse {
match QueryAirport::get(&icao.into_inner()) {
Ok(a) => {
let airport: Airport = a.into();
HttpResponse::Ok().json(Response {
data: airport,
meta: Some(Metadata {
page: 1,
limit: 1,
pages: 1,
total: 1,
}),
})
HttpResponse::Ok().json(airport)
}
Err(err) => {
error!("{}", err);
@@ -232,7 +222,7 @@ async fn get(icao: web::Path<String>) -> HttpResponse {
}
#[post("")]
async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
async fn create_airport(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
let _ = match verify_role(&auth, "admin") {
Ok(_) => {}
Err(err) => return ResponseError::error_response(&err),
@@ -251,7 +241,7 @@ async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
}
#[put("/{icao}")]
async fn update(
async fn update_airport(
_icao: web::Path<String>,
airport: web::Json<Airport>,
auth: JwtAuth,
@@ -274,7 +264,7 @@ async fn update(
}
#[delete("")]
async fn delete_all(auth: JwtAuth) -> HttpResponse {
async fn delete_airports(auth: JwtAuth) -> HttpResponse {
let _ = match verify_role(&auth, "admin") {
Ok(_) => {}
Err(err) => return ResponseError::error_response(&err),
@@ -289,7 +279,7 @@ async fn delete_all(auth: JwtAuth) -> HttpResponse {
}
#[delete("/{icao}")]
async fn delete(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
async fn delete_airport(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
let _ = match verify_role(&auth, "admin") {
Ok(_) => {}
Err(err) => return ResponseError::error_response(&err),
@@ -306,12 +296,12 @@ async fn delete(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
pub fn init_routes(config: &mut web::ServiceConfig) {
config.service(
web::scope("airports")
.service(get_all)
.service(get)
.service(create)
.service(update)
.service(delete)
.service(delete_all)
.service(import),
.service(import_airports)
.service(get_airports)
.service(get_airport)
.service(create_airport)
.service(update_airport)
.service(delete_airports)
.service(delete_airport),
);
}

View File

@@ -158,7 +158,6 @@ pub struct Response<T> {
pub struct Metadata {
pub page: i32,
pub limit: i32,
pub pages: i64,
pub total: i64,
}

View File

@@ -22,7 +22,7 @@ async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,service=info"));
db::init().await;
scheduler::update_airports();
// scheduler::update_airports();
let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string());
let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string());

View File

@@ -24,7 +24,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
};
let airports =
let metars =
match web::block(|| Ok::<_, ServiceError>(async { Metar::get_all(icao_string).await }))
.await
.unwrap()
@@ -37,15 +37,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
return err.to_http_response();
}
};
HttpResponse::Ok().json(MetarsResponse {
data: airports,
meta: Metadata {
page: 0,
limit: 0,
pages: 0,
total: 0,
},
})
HttpResponse::Ok().json(metars)
}
pub fn init_routes(config: &mut web::ServiceConfig) {

View File

@@ -1,13 +1,13 @@
import { Airport, AirportOrderField, Bounds, GetAirportResponse, GetAirportsResponse } from './airport.types';
import { Airport, AirportOrderField, Bounds, GetAirportsResponse } from './airport.types';
import { getRequest, deleteRequest, postRequest, putRequest } from '.';
interface GetAirportProps {
icao: string;
}
export async function getAirport({ icao }: GetAirportProps): Promise<GetAirportResponse> {
export async function getAirport({ icao }: GetAirportProps): Promise<Airport> {
const response = await getRequest(`airports/${icao}`);
return response?.json() || { data: undefined };
return response?.json() || {};
}
interface GetAirportsProps {

View File

@@ -86,11 +86,6 @@ export interface Frequency {
frequency_mhz: number;
}
export interface GetAirportResponse {
data: Airport;
meta: Metadata;
}
export interface GetAirportsResponse {
data: Airport[];
meta: Metadata;

View File

@@ -75,6 +75,5 @@ export async function deleteRequest(endpoint: string): Promise<Response> {
export interface Metadata {
limit: number;
page: number;
pages: number;
total: number;
}

View File

@@ -1,15 +1,11 @@
import { Metar } from './metar.types';
import { getRequest } from '.';
interface GetMetarsResponse {
data: Metar[];
}
export async function getMetars(icaos: string[]): Promise<GetMetarsResponse> {
export async function getMetars(icaos: string[]): Promise<Metar[]> {
if (icaos.length == 0) {
return { data: [] };
return [];
}
const stationICAOs: string = icaos.map((icao) => icao).join(',');
const response = await getRequest(`metars`, { icaos: stationICAOs });
return response?.json() || { data: [] };
return response?.json() || [];
}

View File

@@ -13,9 +13,9 @@ export default function Page({ params }: { params: { icao: string } }) {
useEffect(() => {
async function loadAirport() {
const { data: airportData } = await getAirport({ icao: params.icao });
const airportData = await getAirport({ icao: params.icao });
setAirport(airportData);
const { data: metarData } = await getMetars([airportData.icao]);
const metarData = await getMetars([airportData.icao]);
if (metarData.length > 0) {
setMetar(metarData[0]);
}

View File

@@ -57,7 +57,7 @@ export default function MapTiles() {
page: 1
});
const airports = airportData.filter((airport) => airport.has_metar);
const { data: metars } = await getMetars(airports.map((a) => a.icao));
const metars = await getMetars(airports.map((a) => a.icao));
metars.forEach((metar) => {
airportData.forEach((airport) => {
if (metar.station_id == airport.icao) {