from . import const from . import rpccommon from .common import MAVA_BASE_URL, fixUnpickled import jsonrpclib import hashlib import datetime import calendar import sys import ssl import certifi #--------------------------------------------------------------------------------------- class RPCObject(object): """Base class for objects read from RPC calls. It is possible to construct it from a dictionary.""" def __init__(self, value, instructions = {}): """Construct the object. value is the dictionary returned by the call. info is a mapping from names to 'instructions' on what to do with the corresponding values. If the instruction is None, it will be ignored. If the instruction is a function, the value will be passed to it and the return value will be stored in the object. For all other names, the value will be stored as the same-named attribute.""" for (key, value) in value.items(): if key in instructions: instruction = instructions[key] if instruction is None: continue try: value = instruction(value) except: print("Failed to convert value '%s' of attribute '%s':" % \ (value, key), file=sys.stderr) import traceback traceback.print_exc() setattr(self, key, value) #--------------------------------------------------------------------------------------- class Reply(RPCObject): """The generic reply structure.""" #--------------------------------------------------------------------------------------- class ScheduledFlight(RPCObject): """A scheduled flight in the time table.""" # The instructions for the construction # Type: normal flight TYPE_NORMAL = 0 # Type: VIP flight TYPE_VIP = 1 _instructions = { "id" : int, "pairID": int, "typeCode": lambda value: BookedFlight._decodeAircraftType(value), "departureTime": lambda value: ScheduledFlight._decodeTime(value), "arrivalTime": lambda value: ScheduledFlight._decodeTime(value), "duration": lambda value: ScheduledFlight._decodeDuration(value), "spec": int, "validFrom": lambda value: ScheduledFlight._decodeDate(value), "validTo": lambda value: ScheduledFlight._decodeDate(value), "date": lambda value: ScheduledFlight._decodeDate(value) } @staticmethod def _decodeTime(value): """Decode the given value as a time value.""" return datetime.datetime.strptime(value, "%H:%M:%S").time() @staticmethod def _decodeDate(value): """Decode the given value as a date value.""" if not value or value=="0000-00-00": return const.defaultDate else: return datetime.datetime.strptime(value, "%Y-%m-%d").date() @staticmethod def _decodeDuration(value): """Decode the given value as a duration. A number of seconds will be returned.""" t = datetime.datetime.strptime(value, "%H:%M:%S") return (t.hour*60 + t.minute) * 60 + t.second def __init__(self, value): """Construct the scheduled flight object from the given JSON value.""" super(ScheduledFlight, self).__init__(value, ScheduledFlight._instructions) self.aircraftType = self.typeCode del self.typeCode self.type = ScheduledFlight.TYPE_VIP if self.spec==1 \ else ScheduledFlight.TYPE_NORMAL del self.spec def compareBy(self, other, name): """Compare this flight with the other one according to the given attribute name.""" if name=="callsign": try: cs1 = int(self.callsign[2:]) cs2 = int(other.callsign[2:]) return 0 if cs1==cs2 else -1 if cs1 %d, %d>" % \ (self.id, self.pairID, BookedFlight.TYPE2TYPECODE[self.aircraftType], self.departureICAO, str(self.departureTime), self.arrivalICAO, str(self.arrivalTime), self.duration, self.type) #--------------------------------------------------------------------------------------- class ScheduledFlightPair(object): """A pair of scheduled flights. Occasionally, one of the flights may be missing.""" @staticmethod def scheduledFlights2Pairs(scheduledFlights, date): """Convert the given list of scheduled flights into a list of flight pairs.""" weekday = str(date.weekday()+1) flights = {} weekdayFlights = {} for flight in scheduledFlights: flights[flight.id] = flight if (flight.type==ScheduledFlight.TYPE_NORMAL and flight.arrivalICAO!="LHBP" and weekday in flight.days and flight.validFrom<=date and flight.validTo>=date) or \ flight.type==ScheduledFlight.TYPE_VIP: weekdayFlights[flight.id] = flight flightPairs = [] while weekdayFlights: (id, flight) = weekdayFlights.popitem() if flight.type==ScheduledFlight.TYPE_NORMAL: pairID = flight.pairID if pairID in flights: pairFlight = flights[pairID] if flight.departureICAO=="LHBP" or \ (pairFlight.departureICAO!="LHBP" and flight.callsign" % \ (self.flight0.callsign, self.flight0.departureICAO, self.flight0.arrivalICAO) #--------------------------------------------------------------------------------------- class BookedFlight(RPCObject): """A booked flight.""" TYPECODE2TYPE = { "B736" : const.AIRCRAFT_B736, "736" : const.AIRCRAFT_B736, "B737" : const.AIRCRAFT_B737, "73G" : const.AIRCRAFT_B737, "B738" : const.AIRCRAFT_B738, "738" : const.AIRCRAFT_B738, "B73H" : const.AIRCRAFT_B738C, "73H" : const.AIRCRAFT_B738C, "B732" : const.AIRCRAFT_B732, "732" : const.AIRCRAFT_B732, "B733" : const.AIRCRAFT_B733, "733" : const.AIRCRAFT_B733, "B734" : const.AIRCRAFT_B734, "734" : const.AIRCRAFT_B734, "B735" : const.AIRCRAFT_B735, "735" : const.AIRCRAFT_B735, "DH8D" : const.AIRCRAFT_DH8D, "DH4" : const.AIRCRAFT_DH8D, "B762" : const.AIRCRAFT_B762, "762" : const.AIRCRAFT_B762, "B763" : const.AIRCRAFT_B763, "763" : const.AIRCRAFT_B763, "CRJ2" : const.AIRCRAFT_CRJ2, "CR2" : const.AIRCRAFT_CRJ2, "F70" : const.AIRCRAFT_F70, "LI2" : const.AIRCRAFT_DC3, "T134" : const.AIRCRAFT_T134, "TU3" : const.AIRCRAFT_T134, "T154" : const.AIRCRAFT_T154, "TU5" : const.AIRCRAFT_T154, "YK40" : const.AIRCRAFT_YK40, "YK4" : const.AIRCRAFT_YK40, "B462" : const.AIRCRAFT_B462, "146" : const.AIRCRAFT_B462, "IL62" : const.AIRCRAFT_IL62 } TYPE2TYPECODE = { const.AIRCRAFT_B736 : "B736", const.AIRCRAFT_B737 : "B737", const.AIRCRAFT_B738 : "B738", const.AIRCRAFT_B738C : "B73H", const.AIRCRAFT_B732 : "B732", const.AIRCRAFT_B733 : "B733", const.AIRCRAFT_B734 : "B734", const.AIRCRAFT_B735 : "B735", const.AIRCRAFT_DH8D : "DH8D", const.AIRCRAFT_B762 : "B762", const.AIRCRAFT_B763 : "B763", const.AIRCRAFT_CRJ2 : "CRJ2", const.AIRCRAFT_F70 : "F70", const.AIRCRAFT_DC3 : "LI2", const.AIRCRAFT_T134 : "T134", const.AIRCRAFT_T154 : "T155", const.AIRCRAFT_YK40 : "YK40", const.AIRCRAFT_B462 : "B462", const.AIRCRAFT_IL62 : "IL62" } checkFlightTypes = [ const.AIRCRAFT_B736, const.AIRCRAFT_B737, const.AIRCRAFT_B738, const.AIRCRAFT_DH8D ] @staticmethod def _decodeAircraftType(typeCode): """Decode the aircraft type from the given typeCode.""" if typeCode in BookedFlight.TYPECODE2TYPE: return BookedFlight.TYPECODE2TYPE[typeCode] else: raise Exception("Invalid aircraft type code: '" + typeCode + "'") @staticmethod def _decodeStatus(status): """Decode the status from the status string.""" if status=="booked": return BookedFlight.STATUS_BOOKED elif status=="reported": return BookedFlight.STATUS_REPORTED elif status=="accepted": return BookedFlight.STATUS_ACCEPTED elif status=="rejected": return BookedFlight.STATUS_REJECTED else: raise Exception("Invalid flight status code: '" + status + "'") @staticmethod def _convertFlightType(ft): """Convert the in-database flight-type to one of our constants.""" ft = int(ft) if ft==0: return const.FLIGHTTYPE_SCHEDULED elif ft==1: return const.FLIGHTTYPE_VIP elif ft==2: return const.FLIGHTTYPE_CHARTER else: return const.FLIGHTTYPE_SCHEDULED @staticmethod def getDateTime(date, time): """Get a datetime object from the given textual date and time.""" return datetime.datetime.strptime(date + " " + time, "%Y-%m-%d %H:%M:%S") STATUS_BOOKED = 1 STATUS_REPORTED = 2 STATUS_ACCEPTED = 3 STATUS_REJECTED = 4 @staticmethod def forCheckFlight(aircraftType): """Create a booked flight for a check flight with the given aircraft type.""" flight = BookedFlight() flight.departureICAO = "LHBP" flight.arrivalICAO = "LHBP" flight.aircraftType = aircraftType flight.aircraftTypeName = BookedFlight.TYPE2TYPECODE[aircraftType] # FIXME: perhaps find one for the type flight.tailNumber = "HA-CHK" flight.callsign = "HA-CHK" flight.numPassengers = 0 flight.numChildren = 0 flight.numInfants = 0 flight.numCabinCrew = 0 flight.bagWeight = 0 flight.cargoWeight = 0 flight.mailWeight = 0 flight.route = "DCT" t = datetime.datetime.now() + datetime.timedelta(minutes = 20) flight.departureTime = datetime.datetime(t.year, t.month, t.day, t.hour, t.minute) t = flight.departureTime + datetime.timedelta(minutes = 30) flight.arrivalTime = datetime.datetime(t.year, t.month, t.day, t.hour, t.minute) return flight # The instructions for the construction _instructions = { "numPassengers" : int, "numChildren" : int, "numInfants" : int, "numCabinCrew" : int, "dowNumCabinCrew" : int, "numCockpitCrew" : int, "bagWeight" : int, "cargoWeight" : int, "mailWeight" : int, "flightType" : lambda value: BookedFlight._convertFlightType(value), "dow": int, "maxPassengers": int, "aircraftType" : lambda value: BookedFlight._decodeAircraftType(value), "status" : lambda value: BookedFlight._decodeStatus(value) } def __init__(self, value = None, id = None): """Construct the booked flight object from the given RPC result value.""" self.status = BookedFlight.STATUS_BOOKED if value is None: self.id = id else: super(BookedFlight, self).__init__(value, BookedFlight._instructions) self.departureTime = \ BookedFlight.getDateTime(self.date, self.departureTime) self.arrivalTime = \ BookedFlight.getDateTime(self.date, self.arrivalTime) if self.arrivalTime=0: line = line[:hashIndex] if line: equalIndex = line.find("=") lineOK = equalIndex>0 if lineOK: key = line[:equalIndex].strip() value = line[equalIndex+1:].strip().replace("\:", ":") lineOK = key and value if lineOK: if key=="callsign": self.callsign = value elif key=="date": date = value elif key=="dep_airport": self.departureICAO = value elif key=="dest_airport": self.arrivalICAO = value elif key=="planecode": self.aircraftType = \ BookedFlight._decodeAircraftType(value) elif key=="planetype": self.aircraftTypeName = value elif key=="tail_nr": self.tailNumber = value elif key=="passenger": self.numPassengers = int(value) elif key=="child": self.numChildren = int(value) elif key=="infant": self.numInfants = int(value) elif key=="crew": self.numCabinCrew = int(value) - 2 elif key=="cabin_crew": self.numCabinCrew = int(value) elif key=="cockpit_crew": self.numCockpitCrew = int(value) elif key=="bag": self.bagWeight = int(value) elif key=="cargo": self.cargoWeight = int(value) elif key=="mail": self.mailWeight = int(value) elif key=="flight_route": self.route = value elif key=="departure_time": departureTime = value elif key=="arrival_time": arrivalTime = value elif key=="foglalas_id": self.id = None if value=="0" else value elif key=="flight_type": self.flightType = int(value) else: lineOK = False if not lineOK: print("web.BookedFlight.readFromFile: line %d is invalid" % \ (lineNumber,)) line = f.readline() if date is not None: if departureTime is not None: self.departureTime = BookedFlight.getDateTime(date, departureTime) if arrivalTime is not None: self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime) d = dir(self) for attribute in ["callsign", "departureICAO", "arrivalICAO", "aircraftType", "tailNumber", "numPassengers", "numCockpitCrew", "numCabinCrew", "bagWeight", "cargoWeight", "mailWeight", "route", "departureTime", "arrivalTime"]: if attribute not in d: raise Exception("Attribute %s could not be read" % (attribute,)) if "aircraftTypeName" not in d: self.aircraftTypeName = \ BookedFlight.TYPE2TYPECODE[self.aircraftType] plane = fleet[self.tailNumber] if plane is None: self.dow = 0 self.maxPassengers = 0 self.dowNumCabinCrew = 0 else: self.dow = plane.dow self.maxPassengers = plane.maxPassengers self.dowNumCabinCrew = plane.dowNumCabinCrew def setupFromPIREPData(self, pirepData): """Setup the booked flight from the given PIREP data.""" bookedFlightData = pirepData["bookedFlight"] self.callsign = bookedFlightData["callsign"] date = bookedFlightData["date"] departureTime = bookedFlightData["departureTime"] self.departureTime = BookedFlight.getDateTime(date, departureTime) arrivalTime = bookedFlightData["arrivalTime"] self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime) if self.arrivalTime