-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathservices.py
More file actions
117 lines (92 loc) · 3.34 KB
/
services.py
File metadata and controls
117 lines (92 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from __future__ import annotations
import time
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from datetime import datetime
from typing import Callable
from config import KST, TERMINALS
from models import FlightItem, FlightType
from flight_api import fetch_flights
@dataclass(slots=True)
class GateFlight:
item: FlightItem
flight_type: FlightType
parsed_time: datetime
@dataclass(slots=True)
class TaggedFlight:
item: FlightItem
flight_type: FlightType
# ── Gate Search ──
def fetch_gate_flights(
search_date: str,
gate: str,
search_from: str,
) -> tuple[list[GateFlight], float]:
start = time.time()
with ThreadPoolExecutor(max_workers=2) as executor:
future_arrivals = executor.submit(
fetch_flights, FlightType.ARRIVAL, search_date, searchFrom=search_from,
)
future_departures = executor.submit(
fetch_flights, FlightType.DEPARTURE, search_date, searchFrom=search_from,
)
arrivals = future_arrivals.result()
departures = future_departures.result()
elapsed = time.time() - start
print(f"[게이트 조회] API 병렬 소요시간: {elapsed:.2f}초")
result = (
_filter_by_gate(arrivals, gate, FlightType.ARRIVAL)
+ _filter_by_gate(departures, gate, FlightType.DEPARTURE)
)
return result, elapsed
def filter_future_flights(
gate_flights: list[GateFlight],
cutoff: datetime,
) -> list[GateFlight]:
future = [gf for gf in gate_flights if gf.parsed_time >= cutoff]
future.sort(key=lambda gf: gf.parsed_time)
return future
def _filter_by_gate(
flights: list[FlightItem],
gate: str,
flight_type: FlightType,
) -> list[GateFlight]:
result: list[GateFlight] = []
for item in flights:
if not item.is_master:
continue
if item.gate_number.strip().upper() != gate:
continue
parsed = _parse_scheduled(item.scheduled_datetime)
if parsed is None:
continue
result.append(GateFlight(item=item, flight_type=flight_type, parsed_time=parsed))
return result
def _parse_scheduled(raw: str) -> datetime | None:
if not raw or raw == "-":
return None
try:
return datetime.strptime(raw.strip(), "%Y%m%d%H%M").replace(tzinfo=KST)
except ValueError:
return None
# ── Excel Download ──
def fetch_excel_data(
dates: list[str],
target_terminal_id: str,
progress_callback: Callable[[str, str], None] | None = None,
) -> dict[str, list[TaggedFlight]]:
terminal_items: dict[str, list[TaggedFlight]] = {t.terminal_id: [] for t in TERMINALS}
for date_string in dates:
if progress_callback:
progress_callback(date_string, "departure")
departures = fetch_flights(FlightType.DEPARTURE, date_string)
if progress_callback:
progress_callback(date_string, "arrival")
arrivals = fetch_flights(FlightType.ARRIVAL, date_string)
for flight_type, flights in ((FlightType.DEPARTURE, departures), (FlightType.ARRIVAL, arrivals)):
for item in flights:
if item.terminal_id == target_terminal_id:
terminal_items[item.terminal_id].append(
TaggedFlight(item=item, flight_type=flight_type)
)
return terminal_items