|
@@ -0,0 +1,213 @@
|
|
|
+import {
|
|
|
+ Body,
|
|
|
+ Controller,
|
|
|
+ Get,
|
|
|
+ Delete,
|
|
|
+ Post,
|
|
|
+ Query,
|
|
|
+ HttpException,
|
|
|
+ HttpStatus,
|
|
|
+} from '@nestjs/common';
|
|
|
+import { ApiBody, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
|
|
+import { AirportService } from 'src/airport/airport.service';
|
|
|
+import { CoordinateConverter, WaypointConverter } from 'src/generic/converters';
|
|
|
+import { CoordinateDto } from 'src/generic/dto/coordinate.dto';
|
|
|
+import { WaypointDto } from 'src/generic/dto/waypoint.dto';
|
|
|
+import { AircraftDto } from './dto/aircraft.dto';
|
|
|
+import { ControllerInputDto } from './dto/controllerinput.dto';
|
|
|
+import { FlightStateDto } from './dto/flightstate.dto';
|
|
|
+import { InboundDto } from './dto/inbound.dto';
|
|
|
+import { PlanningDto } from './dto/planning.dto';
|
|
|
+import { PredictedWaypointDto } from './dto/predictedwaypoint.dto';
|
|
|
+import { InboundService } from './inbound.service';
|
|
|
+import { Aircraft } from './models/aircraft.model';
|
|
|
+import { ControllerInput } from './models/controllerinput.model';
|
|
|
+import { FlightState } from './models/flightstate.model';
|
|
|
+import { Inbound } from './models/inbound.model';
|
|
|
+import { Planning } from './models/planning.model';
|
|
|
+import { PredictedWaypoint } from './models/predictedwaypoint.model';
|
|
|
+
|
|
|
+@Controller('inbound')
|
|
|
+export class InboundController {
|
|
|
+ constructor(
|
|
|
+ private readonly inboundService: InboundService,
|
|
|
+ private readonly airportService: AirportService,
|
|
|
+ ) {}
|
|
|
+
|
|
|
+ private static convertAircraft<T>(aircraft: Aircraft | AircraftDto): T {
|
|
|
+ return {
|
|
|
+ type: aircraft.type,
|
|
|
+ wtc: aircraft.wtc,
|
|
|
+ wakeRecat: aircraft.wakeRecat,
|
|
|
+ engineCount: aircraft.engineCount,
|
|
|
+ engineType: aircraft.engineType,
|
|
|
+ } as T;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertControllerInput<T>(
|
|
|
+ input: ControllerInput | ControllerInputDto,
|
|
|
+ ): T {
|
|
|
+ return {
|
|
|
+ reportedTime: input.reportedTime,
|
|
|
+ remainingRoute: WaypointConverter.convertList(input.remainingRoute),
|
|
|
+ requestedRunway: input.requestedRunway,
|
|
|
+ plannedStand: input.plannedStand,
|
|
|
+ } as T;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertFlightState<T>(input: FlightState | FlightStateDto): T {
|
|
|
+ return {
|
|
|
+ position: CoordinateConverter.convert(input.position),
|
|
|
+ groundSpeed: input.groundSpeed,
|
|
|
+ groundTrack: input.groundTrack,
|
|
|
+ altitude: input.altitude,
|
|
|
+ verticalSpeed: input.verticalSpeed,
|
|
|
+ } as T;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertPredictedWaypoints(
|
|
|
+ waypoints: PredictedWaypoint[],
|
|
|
+ ): PredictedWaypointDto[] {
|
|
|
+ const retval: PredictedWaypointDto[] = [];
|
|
|
+ waypoints.forEach((input) =>
|
|
|
+ retval.push({
|
|
|
+ waypoint: WaypointConverter.convert<WaypointDto, CoordinateDto>(
|
|
|
+ input.waypoint,
|
|
|
+ ),
|
|
|
+ altitude: input.altitude,
|
|
|
+ indicatedAirspeed: input.indicatedAirspeed,
|
|
|
+ groundspeed: input.groundspeed,
|
|
|
+ plannedOverheadTime: input.plannedOverheadTime,
|
|
|
+ }),
|
|
|
+ );
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertPlanning(plan: Planning): PlanningDto {
|
|
|
+ if (plan === undefined) return undefined;
|
|
|
+
|
|
|
+ return {
|
|
|
+ arrivalRoute: plan.arrivalRoute,
|
|
|
+ arrivalRunway: plan.arrivalRunway,
|
|
|
+ plannedRoute: InboundController.convertPredictedWaypoints(
|
|
|
+ plan.plannedRoute,
|
|
|
+ ),
|
|
|
+ fixedPlan: plan.fixedPlan,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertInboundToInboundDto(inbound: Inbound): InboundDto {
|
|
|
+ return {
|
|
|
+ callsign: inbound.callsign,
|
|
|
+ destination: inbound.destination,
|
|
|
+ reporter: inbound.reporter,
|
|
|
+ aircraft: InboundController.convertAircraft(inbound.aircraft),
|
|
|
+ flightState: InboundController.convertFlightState(inbound.flightState),
|
|
|
+ controllerData: InboundController.convertControllerInput(
|
|
|
+ inbound.controllerData,
|
|
|
+ ),
|
|
|
+ plan: InboundController.convertPlanning(inbound.plan),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private static convertInboundDtoInbound(inbound: InboundDto): Inbound {
|
|
|
+ return {
|
|
|
+ callsign: inbound.callsign,
|
|
|
+ destination: inbound.destination,
|
|
|
+ reporter: inbound.reporter,
|
|
|
+ aircraft: InboundController.convertAircraft(inbound.aircraft),
|
|
|
+ flightState: InboundController.convertFlightState(inbound.flightState),
|
|
|
+ controllerData: InboundController.convertControllerInput(
|
|
|
+ inbound.controllerData,
|
|
|
+ ),
|
|
|
+ plan: undefined,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ @Get('/inbounds')
|
|
|
+ @ApiQuery({
|
|
|
+ name: 'icao',
|
|
|
+ description: 'The ICAO code of the airport',
|
|
|
+ type: String,
|
|
|
+ })
|
|
|
+ @ApiResponse({
|
|
|
+ status: 200,
|
|
|
+ description: 'All known inbounds',
|
|
|
+ type: [InboundDto],
|
|
|
+ })
|
|
|
+ async inbounds(@Query('icao') icao: string): Promise<InboundDto[]> {
|
|
|
+ return this.inboundService.airportInbounds(icao).then((inbounds) => {
|
|
|
+ if (!inbounds) {
|
|
|
+ throw new HttpException(
|
|
|
+ 'No inbounds for the airport found',
|
|
|
+ HttpStatus.NOT_FOUND,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ const retval: InboundDto[] = [];
|
|
|
+ inbounds.forEach((inbound) =>
|
|
|
+ retval.push(InboundController.convertInboundToInboundDto(inbound)),
|
|
|
+ );
|
|
|
+
|
|
|
+ return retval;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Post('/insert')
|
|
|
+ @ApiBody({
|
|
|
+ description: 'The new or updated inbound',
|
|
|
+ type: InboundDto,
|
|
|
+ })
|
|
|
+ @ApiResponse({
|
|
|
+ status: 201,
|
|
|
+ description: 'Inserted or updated the inbound',
|
|
|
+ })
|
|
|
+ @ApiResponse({
|
|
|
+ status: 404,
|
|
|
+ description: 'The destination airport is unknown',
|
|
|
+ })
|
|
|
+ async insert(inbound: InboundDto): Promise<boolean> {
|
|
|
+ return this.airportService.airport(inbound.destination).then((airport) => {
|
|
|
+ if (!airport) {
|
|
|
+ throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
|
|
|
+ }
|
|
|
+
|
|
|
+ return this.inboundService
|
|
|
+ .callsignKnown(inbound.callsign)
|
|
|
+ .then((known) => {
|
|
|
+ const internalInbound =
|
|
|
+ InboundController.convertInboundDtoInbound(inbound);
|
|
|
+
|
|
|
+ if (known) {
|
|
|
+ return this.inboundService.update(internalInbound);
|
|
|
+ } else {
|
|
|
+ return this.inboundService.add(internalInbound);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Delete('/remove')
|
|
|
+ @ApiQuery({
|
|
|
+ name: 'callsign',
|
|
|
+ description: 'The callsign of the inbound',
|
|
|
+ type: String,
|
|
|
+ })
|
|
|
+ @ApiResponse({
|
|
|
+ status: 200,
|
|
|
+ description: 'The inbound is deleted',
|
|
|
+ })
|
|
|
+ @ApiResponse({
|
|
|
+ status: 404,
|
|
|
+ description: 'The inbound is unknown',
|
|
|
+ })
|
|
|
+ async remove(@Query('callsign') callsign: string): Promise<void> {
|
|
|
+ await this.inboundService.callsignKnown(callsign).then(async (known) => {
|
|
|
+ if (!known) {
|
|
|
+ throw new HttpException('Inbound not found', HttpStatus.NOT_FOUND);
|
|
|
+ }
|
|
|
+
|
|
|
+ await this.inboundService.remove(callsign);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|