242 lines
7.1 KiB
TypeScript
242 lines
7.1 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Delete,
|
|
Post,
|
|
Query,
|
|
HttpException,
|
|
HttpStatus,
|
|
} from '@nestjs/common';
|
|
import { ApiBody, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
|
import { AirportService } from '../airport/airport.service';
|
|
import { CoordinateConverter, WaypointConverter } from '../generic/converters';
|
|
import { CoordinateDto } from '../generic/dto/coordinate.dto';
|
|
import { WaypointDto } from '../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 waypointsDtoToPredictedWaypoints(
|
|
waypoints: WaypointDto[],
|
|
): PredictedWaypoint[] {
|
|
const retval: PredictedWaypoint[] = [];
|
|
waypoints.forEach((waypoint) =>
|
|
retval.push({
|
|
waypoint: WaypointConverter.convert(waypoint),
|
|
altitude: undefined,
|
|
indicatedAirspeed: undefined,
|
|
groundspeed: undefined,
|
|
plannedOverheadTime: undefined,
|
|
}),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static convertControllerInput<T>(
|
|
input: ControllerInput | ControllerInputDto,
|
|
): T {
|
|
if (input instanceof ControllerInputDto) {
|
|
return {
|
|
reportedTime: input.reportedTime,
|
|
remainingRoute: InboundController.waypointsDtoToPredictedWaypoints(
|
|
input.remainingRoute,
|
|
),
|
|
requestedRunway: input.requestedRunway,
|
|
plannedStand: input.plannedStand,
|
|
} as T;
|
|
} else {
|
|
return {
|
|
reportedTime: input.reportedTime,
|
|
remainingRoute: InboundController.convertPredictedWaypoints(
|
|
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);
|
|
});
|
|
}
|
|
}
|