diff --git a/prisma/migrations/20250926144945_add_route/migration.sql b/prisma/migrations/20250926144945_add_route/migration.sql new file mode 100644 index 0000000..82bbfcf --- /dev/null +++ b/prisma/migrations/20250926144945_add_route/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "public"."Flight" ADD COLUMN "route" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9ade743..fd20d5b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -38,6 +38,8 @@ model Flight { destinationName String // airport name destinationCity String // city name destinationTimezone String // string timezone "region/capital" + + route String? // textual route // timing (stored in iso 8601 format on the api) scheduledOut DateTime? diff --git a/src/index.ts b/src/index.ts index 3c243ed..3c2c134 100644 --- a/src/index.ts +++ b/src/index.ts @@ -321,6 +321,7 @@ app.action('flight_selection', async ({ body, ack, respond }) => { destinationName: flightData.destination.name, destinationCity: flightData.destination.city, destinationTimezone: flightData.destination.timezone, + route: flightData.route, scheduledOut: flightData.scheduled_out, scheduledOff: flightData.scheduled_off, scheduledOn: flightData.scheduled_on, diff --git a/src/util/flightAware.ts b/src/util/flightAware.ts index 6f9667a..70ed79b 100644 --- a/src/util/flightAware.ts +++ b/src/util/flightAware.ts @@ -209,7 +209,7 @@ export interface Flight { route_distance: number; filed_airspeed: number; filed_altitude: null; - route: null; + route: string | null; baggage_claim: null; seats_cabin_business: null; seats_cabin_coach: null; diff --git a/src/util/flightUpdater.ts b/src/util/flightUpdater.ts index a31210e..cc51ce1 100644 --- a/src/util/flightUpdater.ts +++ b/src/util/flightUpdater.ts @@ -52,18 +52,21 @@ export class FlightUpdater { const currentlyTracked = new Set(this.flightIntervals.keys()); const activeFlightIds = new Set(flights.map((f) => f.id)); - // remove intervals for flights no longer active for (const flightId of currentlyTracked) { if (!activeFlightIds.has(flightId)) { - clearInterval(this.flightIntervals.get(flightId)!); - this.flightIntervals.delete(flightId); - console.log(`Stopped tracking flight ${flightId}`); + this.removeFlightPolling(flightId); } } - // add intervals for new flights - for (const flight of flights) { - if (!this.flightIntervals.has(flight.id)) { + for (const flightId of activeFlightIds) { + const existingInterval = this.flightIntervals.get(flightId); + if (existingInterval) { + clearInterval(existingInterval); + this.flightIntervals.delete(flightId); + } + + const flight = flights.find((f) => f.id === flightId); + if (flight) { this.setupFlightPolling(flight); } } @@ -118,7 +121,7 @@ export class FlightUpdater { } if (now < scheduledOff) { - return 3 * 60 * 1000; + return 5 * 60 * 1000; } const inflightWindowEnd = new Date(scheduledOn.getTime() + 2 * 60 * 60 * 1000); @@ -128,13 +131,14 @@ export class FlightUpdater { if (flight.progressPercent > 90) return 5 * 60 * 1000; } else { // first 15 minutes after scheduledOff - if (now < new Date(scheduledOff.getTime() + 15 * 60 * 1000)) { + const offTime = flight.actualOff ? new Date(flight.actualOff) : scheduledOff; + if (now < new Date(offTime.getTime() + 15 * 60 * 1000)) { return 4 * 60 * 1000; } } // cruisin - return 20 * 60 * 1000; + return 30 * 60 * 1000; } // post arrival (eventually deleted) @@ -191,7 +195,6 @@ export class FlightUpdater { if (!currentFlight.actualOff && newData.actual_off) { changes.push('✈️ Flight has taken off!'); - this.adjustFlightPolling(flight.id, flight); } if (!currentFlight.actualOn && newData.actual_on) { @@ -247,6 +250,11 @@ export class FlightUpdater { }, }); + if (!currentFlight.actualOff && newData.actual_off) { + // adjust polling on takeoff + await this.adjustFlightPolling(flight.id, updatedFlight); + } + // stop polling on completion if (updatedFlight.actualIn) { this.removeFlightPolling(flight.id); @@ -266,22 +274,34 @@ export class FlightUpdater { console.error(`error updating flight ${flight.ident}:`, error); // adjust polling for error - this.adjustFlightPolling(flight.id, flight, true); + await this.adjustFlightPolling(flight.id, flight, true); } } - private adjustFlightPolling(flightId: string, flight: Flight, isError: boolean = false) { + private async adjustFlightPolling(flightId: string, flight: Flight, isError: boolean = false) { const existingInterval = this.flightIntervals.get(flightId); if (existingInterval) { clearInterval(existingInterval); + this.flightIntervals.delete(flightId); } - let newInterval = this.calculatePollInterval(flight); + const freshFlight = await db.flight.findUnique({ where: { id: flightId } }); + if (!freshFlight) { + console.log(`Flight ${flightId} no longer exists, not adjusting polling`); + return; + } + + let newInterval = this.calculatePollInterval(freshFlight); if (isError) { - newInterval *= 2; + newInterval *= 2; // backoff on error + newInterval = Math.min(newInterval, 60 * 60 * 1000); // 1 hour cap } + console.log( + `Adjusting polling for flight ${freshFlight.ident} to every ${newInterval / 60000} minutes` + ); + const interval = setInterval(() => this.updateSingleFlightById(flightId), newInterval); this.flightIntervals.set(flightId, interval); }