@@ -656,4 +656,115 @@ router.get('/findRoute', async (req, res) => {
656656 }
657657} ) ;
658658
659+ // GET: /api/data/airports/:icao/status - Get airport status with active controller, flights, runway, and METAR
660+ router . get ( '/airports/:icao/status' , async ( req , res ) => {
661+ try {
662+ const icao = req . params . icao . toUpperCase ( ) ;
663+
664+ const sessions = await mainDb
665+ . selectFrom ( 'sessions' )
666+ . select ( [ 'session_id' , 'created_by' , 'active_runway' , 'created_at' ] )
667+ . where ( 'airport_icao' , '=' , icao )
668+ . where ( 'is_pfatc' , '=' , true )
669+ . orderBy ( 'created_at' , 'desc' )
670+ . limit ( 10 )
671+ . execute ( ) ;
672+
673+ if ( sessions . length === 0 ) {
674+ return res . status ( 404 ) . json ( {
675+ error : 'No active PFATC session found' ,
676+ message : `No PFATC controller is currently online at ${ icao } `
677+ } ) ;
678+ }
679+
680+ let validSession = null ;
681+ let controller = null ;
682+ let flightCount = 0 ;
683+
684+ for ( const session of sessions ) {
685+ const sessionController = await mainDb
686+ . selectFrom ( 'users' )
687+ . select ( [ 'id' , 'username' , 'avatar' ] )
688+ . where ( 'id' , '=' , session . created_by )
689+ . executeTakeFirst ( ) ;
690+
691+ if ( ! sessionController ) {
692+ continue ;
693+ }
694+
695+ let sessionFlightCount = 0 ;
696+ try {
697+ const tableName = `flights_${ session . session_id } ` ;
698+ const result = await flightsDb
699+ . selectFrom ( tableName )
700+ . select ( sql `count(*)` . as ( 'count' ) )
701+ . executeTakeFirst ( ) ;
702+ sessionFlightCount = parseInt ( result ?. count as string , 10 ) || 0 ;
703+ } catch {
704+ sessionFlightCount = 0 ;
705+ }
706+
707+ if ( sessionFlightCount > 0 ) {
708+ validSession = session ;
709+ controller = sessionController ;
710+ flightCount = sessionFlightCount ;
711+ break ;
712+ }
713+ }
714+
715+ if ( ! validSession || ! controller ) {
716+ return res . status ( 404 ) . json ( {
717+ error : 'No active PFATC session found' ,
718+ message : `No PFATC controller with active flights is currently online at ${ icao } `
719+ } ) ;
720+ }
721+
722+ let metar = null ;
723+ try {
724+ const metarResponse = await fetch (
725+ `https://aviationweather.gov/api/data/metar?ids=${ icao } &format=json` ,
726+ {
727+ headers : {
728+ 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' ,
729+ } ,
730+ }
731+ ) ;
732+
733+ if ( metarResponse . ok ) {
734+ const metarText = await metarResponse . text ( ) ;
735+ if ( metarText && metarText . trim ( ) !== '' ) {
736+ const metarData = JSON . parse ( metarText ) ;
737+ if ( Array . isArray ( metarData ) && metarData . length > 0 ) {
738+ metar = metarData [ 0 ] ;
739+ }
740+ }
741+ }
742+ } catch ( error ) {
743+ console . error ( 'Error fetching METAR:' , error ) ;
744+ }
745+
746+ res . json ( {
747+ icao,
748+ sessionId : validSession . session_id ,
749+ controller : {
750+ id : controller . id ,
751+ username : controller . username ,
752+ avatar : controller . avatar
753+ ? `https://cdn.discordapp.com/avatars/${ controller . id } /${ controller . avatar } .png`
754+ : null ,
755+ } ,
756+ activeRunway : validSession . active_runway ,
757+ flightCount,
758+ createdAt : validSession . created_at ,
759+ metar,
760+ } ) ;
761+ } catch ( error ) {
762+ console . error ( 'Error fetching airport status:' , error ) ;
763+ res . status ( 500 ) . json ( {
764+ error : 'Internal server error' ,
765+ message : 'Failed to fetch airport status' ,
766+ } ) ;
767+ }
768+ } ) ;
769+
659770export default router ;
0 commit comments