[401] | 1 |
|
---|
| 2 | from util import utf2unicode
|
---|
[298] | 3 |
|
---|
| 4 | import const
|
---|
| 5 | import cPickle as pickle
|
---|
[743] | 6 | import datetime
|
---|
| 7 | import time
|
---|
[97] | 8 |
|
---|
| 9 | #------------------------------------------------------------------------------
|
---|
| 10 |
|
---|
[298] | 11 | ## @package mlx.pirep
|
---|
| 12 | #
|
---|
| 13 | # The PIREP module.
|
---|
| 14 | #
|
---|
| 15 | # This module defines only one class, \ref PIREP. It is used to extract and
|
---|
| 16 | # store the information needed for a PIREP. The saved PIREPs are pickled
|
---|
| 17 | # instances of this class.
|
---|
[97] | 18 |
|
---|
| 19 | #------------------------------------------------------------------------------
|
---|
| 20 |
|
---|
| 21 | class PIREP(object):
|
---|
| 22 | """A pilot's report of a flight."""
|
---|
[743] | 23 | _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
|
---|
| 24 | const.FLIGHTTYPE_OLDTIMER : "OT",
|
---|
| 25 | const.FLIGHTTYPE_VIP : "VIP",
|
---|
| 26 | const.FLIGHTTYPE_CHARTER : "CHARTER" }
|
---|
| 27 |
|
---|
[97] | 28 | @staticmethod
|
---|
| 29 | def _formatLine(timeStr, line):
|
---|
| 30 | """Format the given time string and line as needed for the ACARS and
|
---|
| 31 | some other things."""
|
---|
| 32 | return "[" + timeStr + "]-[" + line + "]"
|
---|
[151] | 33 |
|
---|
| 34 | @staticmethod
|
---|
[743] | 35 | def formatTimestampForRPC(t):
|
---|
| 36 | """Format the given timestamp for RPC."""
|
---|
| 37 | return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(t))
|
---|
| 38 |
|
---|
| 39 | @staticmethod
|
---|
[151] | 40 | def load(path):
|
---|
| 41 | """Load a PIREP from the given path.
|
---|
| 42 |
|
---|
| 43 | Returns the PIREP object, or None on error."""
|
---|
| 44 | try:
|
---|
| 45 | with open(path, "rb") as f:
|
---|
[303] | 46 | pirep = pickle.load(f)
|
---|
| 47 | if "numCrew" not in dir(pirep):
|
---|
| 48 | pirep.numCrew = pirep.bookedFlight.numCrew
|
---|
| 49 | if "numPassengers" not in dir(pirep):
|
---|
| 50 | pirep.numPassengers = pirep.bookedFlight.numPassengers
|
---|
| 51 | if "bagWeight" not in dir(pirep):
|
---|
| 52 | pirep.bagWeight = pirep.bookedFlight.bagWeight
|
---|
| 53 | if "mailWeight" not in dir(pirep):
|
---|
| 54 | pirep.mailWeight = pirep.bookedFlight.mailWeight
|
---|
| 55 | return pirep
|
---|
[151] | 56 | except Exception, e:
|
---|
[401] | 57 | print "Failed loading PIREP from %s: %s" % (path,
|
---|
| 58 | utf2unicode(str(e)))
|
---|
[151] | 59 | return None
|
---|
[345] | 60 |
|
---|
[262] | 61 | def __init__(self, flight):
|
---|
| 62 | """Initialize the PIREP from the given flight."""
|
---|
| 63 | self.bookedFlight = flight.bookedFlight
|
---|
[303] | 64 |
|
---|
| 65 | self.numCrew = flight.numCrew
|
---|
| 66 | self.numPassengers = flight.numPassengers
|
---|
| 67 | self.bagWeight = flight.bagWeight
|
---|
[262] | 68 | self.cargoWeight = flight.cargoWeight
|
---|
[303] | 69 | self.mailWeight = flight.mailWeight
|
---|
[345] | 70 |
|
---|
[262] | 71 | self.filedCruiseAltitude = flight.filedCruiseAltitude
|
---|
| 72 | self.cruiseAltitude = flight.cruiseAltitude
|
---|
| 73 | self.route = flight.route
|
---|
[97] | 74 |
|
---|
[262] | 75 | self.departureMETAR = flight.departureMETAR.upper()
|
---|
| 76 | self.arrivalMETAR = flight.arrivalMETAR.upper()
|
---|
[97] | 77 |
|
---|
[262] | 78 | self.departureRunway = flight.departureRunway.upper()
|
---|
| 79 | self.sid = flight.sid.upper()
|
---|
[97] | 80 |
|
---|
[262] | 81 | self.star = flight.star
|
---|
| 82 | self.transition = flight.transition
|
---|
| 83 | self.approachType = flight.approachType.upper()
|
---|
| 84 | self.arrivalRunway = flight.arrivalRunway.upper()
|
---|
[97] | 85 |
|
---|
[262] | 86 | self.flightType = flight.flightType
|
---|
| 87 | self.online = flight.online
|
---|
[97] | 88 |
|
---|
[262] | 89 | self.comments = flight.comments
|
---|
| 90 | self.flightDefects = flight.flightDefects
|
---|
| 91 | self.delayCodes = flight.delayCodes
|
---|
[345] | 92 |
|
---|
[97] | 93 | self.blockTimeStart = flight.blockTimeStart
|
---|
| 94 | self.flightTimeStart = flight.flightTimeStart
|
---|
| 95 | self.flightTimeEnd = flight.flightTimeEnd
|
---|
| 96 | self.blockTimeEnd = flight.blockTimeEnd
|
---|
| 97 | self.flownDistance = flight.flownDistance
|
---|
[102] | 98 | self.fuelUsed = flight.startFuel - flight.endFuel
|
---|
[97] | 99 |
|
---|
[262] | 100 | logger = flight.logger
|
---|
[97] | 101 | self.rating = logger.getRating()
|
---|
| 102 | self.logLines = logger.lines
|
---|
| 103 | self.faultLineIndexes = logger.faultLineIndexes
|
---|
[345] | 104 |
|
---|
[743] | 105 | @property
|
---|
[778] | 106 | def flightDateText(self):
|
---|
| 107 | """Get the text version of the booked flight's departure time."""
|
---|
| 108 | return self.bookedFlight.departureTime.strftime("%Y-%m-%d")
|
---|
| 109 |
|
---|
| 110 | @property
|
---|
[743] | 111 | def flightTypeText(self):
|
---|
| 112 | """Get the text representation of the flight type."""
|
---|
| 113 | return PIREP._flightTypes[self.flightType]
|
---|
| 114 |
|
---|
| 115 | @property
|
---|
| 116 | def blockTimeStartText(self):
|
---|
| 117 | """Get the beginning of the block time in string format."""
|
---|
| 118 | return PIREP.formatTimestampForRPC(self.blockTimeStart)
|
---|
| 119 |
|
---|
| 120 | @property
|
---|
| 121 | def flightTimeStartText(self):
|
---|
| 122 | """Get the beginning of the flight time in string format."""
|
---|
| 123 | return PIREP.formatTimestampForRPC(self.flightTimeStart)
|
---|
| 124 |
|
---|
| 125 | @property
|
---|
| 126 | def flightTimeEndText(self):
|
---|
| 127 | """Get the end of the flight time in string format."""
|
---|
| 128 | return PIREP.formatTimestampForRPC(self.flightTimeEnd)
|
---|
| 129 |
|
---|
| 130 | @property
|
---|
| 131 | def blockTimeEndText(self):
|
---|
| 132 | """Get the end of the block time in string format."""
|
---|
| 133 | return PIREP.formatTimestampForRPC(self.blockTimeEnd)
|
---|
| 134 |
|
---|
[97] | 135 | def getACARSText(self):
|
---|
| 136 | """Get the ACARS text.
|
---|
| 137 |
|
---|
| 138 | This is a specially formatted version of the log without the faults."""
|
---|
| 139 | text = "[MAVA LOGGER X LOG]-[%s]" % (const.VERSION,)
|
---|
| 140 | for index in range(0, len(self.logLines)):
|
---|
| 141 | if index not in self.faultLineIndexes:
|
---|
| 142 | (timeStr, line) = self.logLines[index]
|
---|
| 143 | if timeStr is not None:
|
---|
| 144 | text += PIREP._formatLine(timeStr, line)
|
---|
| 145 | return text
|
---|
| 146 |
|
---|
| 147 | def getRatingText(self):
|
---|
| 148 | """Get the rating text.
|
---|
| 149 |
|
---|
| 150 | This is a specially formatted version of the lines containing the
|
---|
| 151 | faults."""
|
---|
| 152 | text = ""
|
---|
| 153 | for index in self.faultLineIndexes:
|
---|
| 154 | (timeStr, line) = self.logLines[index]
|
---|
| 155 | if timeStr is not None:
|
---|
| 156 | text += PIREP._formatLine(timeStr, line)
|
---|
[345] | 157 | text += "\n"
|
---|
[97] | 158 |
|
---|
| 159 | text += "\n[Flight Rating: %.1f]" % (max(0.0, self.rating),)
|
---|
| 160 |
|
---|
| 161 | return text
|
---|
[345] | 162 |
|
---|
[97] | 163 | def getTimeComment(self):
|
---|
| 164 | """Get the time comment.
|
---|
| 165 |
|
---|
| 166 | This is basically a collection of the delay codes, if any."""
|
---|
[99] | 167 | if not self.delayCodes:
|
---|
| 168 | return "UTC"
|
---|
| 169 | else:
|
---|
| 170 | s = ""
|
---|
| 171 | for code in self.delayCodes:
|
---|
| 172 | if s: s += ", "
|
---|
[437] | 173 | s += code
|
---|
[99] | 174 | return s
|
---|
[97] | 175 |
|
---|
| 176 | def getSTAR(self):
|
---|
| 177 | """Get the STAR and/or the transition."""
|
---|
| 178 | star = self.star if self.star is not None else ""
|
---|
| 179 | if self.transition is not None:
|
---|
| 180 | if star: star += ", "
|
---|
| 181 | star += self.transition
|
---|
| 182 | return star.upper()
|
---|
[151] | 183 |
|
---|
| 184 | def save(self, path):
|
---|
| 185 | """Save the PIREP to the given file.
|
---|
| 186 |
|
---|
| 187 | Returns whether the saving has succeeded."""
|
---|
| 188 | try:
|
---|
| 189 | with open(path, "wb") as f:
|
---|
| 190 | pickle.dump(self, f)
|
---|
[393] | 191 | return None
|
---|
[151] | 192 | except Exception, e:
|
---|
[401] | 193 | error = utf2unicode(str(e))
|
---|
| 194 | print u"Failed saving PIREP to %s: %s" % (path, error)
|
---|
[393] | 195 | return error
|
---|
[743] | 196 |
|
---|
| 197 | def _serialize(self):
|
---|
| 198 | """Serialize the PIREP for JSON-RPC."""
|
---|
| 199 | attrs = {}
|
---|
| 200 | attrs["log"] = self.getACARSText()
|
---|
[778] | 201 | attrs["flightDate"] = self.flightDateText
|
---|
| 202 | attrs["callsign"] = self.bookedFlight.callsign
|
---|
| 203 | attrs["departureICAO"] = self.bookedFlight.departureICAO
|
---|
| 204 | attrs["arrivalICAO"] = self.bookedFlight.arrivalICAO
|
---|
[743] | 205 | attrs["numPassengers"] = self.numPassengers
|
---|
| 206 | attrs["numCrew"] = self.numCrew
|
---|
| 207 | attrs["cargoWeight"] = self.cargoWeight
|
---|
| 208 | attrs["bagWeight"] = self.bagWeight
|
---|
| 209 | attrs["mailWeight"] = self.mailWeight
|
---|
| 210 | attrs["flightType"] = self.flightTypeText
|
---|
| 211 | attrs["online"] = 1 if self.online else 0
|
---|
| 212 | attrs["blockTimeStart"] = self.blockTimeStartText
|
---|
| 213 | attrs["blockTimeEnd"] = self.blockTimeEndText
|
---|
| 214 | attrs["flightTimeStart"] = self.flightTimeStartText
|
---|
| 215 | attrs["flightTimeEnd"] = self.flightTimeEndText
|
---|
| 216 | attrs["timeComment"] = self.getTimeComment()
|
---|
| 217 | attrs["fuelUsed"] = self.fuelUsed
|
---|
| 218 | attrs["departureRunway"] = self.departureRunway
|
---|
| 219 | attrs["arrivalRunway"] = self.arrivalRunway
|
---|
| 220 | attrs["departureMETAR"] = self.departureMETAR
|
---|
| 221 | attrs["arrivalMETAR"] = self.arrivalMETAR
|
---|
| 222 | attrs["filedCruiseLevel"] = self.filedCruiseAltitude / 100.0
|
---|
| 223 | attrs["cruiseLevel"] = self.cruiseAltitude / 100.0
|
---|
| 224 | attrs["sid"] = self.sid
|
---|
| 225 | attrs["route"] = self.route
|
---|
| 226 | attrs["star"] = self.star
|
---|
| 227 | attrs["approachType"] = self.approachType
|
---|
| 228 | attrs["comments"] = self.comments
|
---|
| 229 | attrs["flightDefects"] = self.flightDefects
|
---|
| 230 | attrs["ratingText"] = self.getRatingText()
|
---|
| 231 | attrs["rating"] = max(0.0, self.rating)
|
---|
| 232 | attrs["flownDistance"] = self.flownDistance
|
---|
| 233 | # FIXME: it should be stored in the PIREP when it is sent later
|
---|
[778] | 234 | attrs["performDate"] = datetime.date.today().strftime("%Y-%m-%d")
|
---|
[743] | 235 |
|
---|
| 236 | return ([], attrs)
|
---|