source: src/mlx/web.py@ 184:0a000ef19c3a

Last change on this file since 184:0a000ef19c3a was 184:0a000ef19c3a, checked in by István Váradi <ivaradi@…>, 12 years ago

Added support for the entrance exam

File size: 33.3 KB
Line 
1# Interface towards the websites used
2
3#------------------------------------------------------------------------------
4
5import const
6import util
7
8import threading
9import sys
10import urllib
11import urllib2
12import hashlib
13import time
14import datetime
15import codecs
16import traceback
17import xml.sax
18
19#---------------------------------------------------------------------------------------
20
21def readline(f):
22 """Read a line from the given file.
23
24 The line is stripped and empty lines are discarded."""
25 while True:
26 line = f.readline()
27 if not line: return ""
28 line = line.strip()
29 if line:
30 return line
31
32#---------------------------------------------------------------------------------------
33
34class BookedFlight(object):
35 """A flight that was booked."""
36 TYPECODE2TYPE = { "736" : const.AIRCRAFT_B736,
37 "73G" : const.AIRCRAFT_B737,
38 "738" : const.AIRCRAFT_B738,
39 "733" : const.AIRCRAFT_B733,
40 "734" : const.AIRCRAFT_B734,
41 "735" : const.AIRCRAFT_B735,
42 "DH4" : const.AIRCRAFT_DH8D,
43 "762" : const.AIRCRAFT_B762,
44 "763" : const.AIRCRAFT_B763,
45 "CR2" : const.AIRCRAFT_CRJ2,
46 "F70" : const.AIRCRAFT_F70,
47 "LI2" : const.AIRCRAFT_DC3,
48 "TU3" : const.AIRCRAFT_T134,
49 "TU5" : const.AIRCRAFT_T154,
50 "YK4" : const.AIRCRAFT_YK40 }
51
52 TYPE2TYPECODE = { const.AIRCRAFT_B736 : "736",
53 const.AIRCRAFT_B737 : "73G",
54 const.AIRCRAFT_B738 : "738",
55 const.AIRCRAFT_B733 : "733",
56 const.AIRCRAFT_B734 : "734",
57 const.AIRCRAFT_B735 : "735",
58 const.AIRCRAFT_DH8D : "DH4",
59 const.AIRCRAFT_B762 : "762",
60 const.AIRCRAFT_B763 : "763",
61 const.AIRCRAFT_CRJ2 : "CR2",
62 const.AIRCRAFT_F70 : "F70",
63 const.AIRCRAFT_DC3 : "LI2",
64 const.AIRCRAFT_T134 : "TU3",
65 const.AIRCRAFT_T154 : "TU5",
66 const.AIRCRAFT_YK40 : "YK4" }
67
68 @staticmethod
69 def getDateTime(date, time):
70 """Get a datetime object from the given textual date and time."""
71 return datetime.datetime.strptime(date + " " + time,
72 "%Y-%m-%d %H:%M:%S")
73
74 def __init__(self, id = None):
75 """Construct a booked flight with the given ID."""
76 self.id = id
77
78 def readFromWeb(self, f):
79 """Read the data of the flight from the web via the given file
80 object."""
81 self.callsign = readline(f)
82
83 date = readline(f)
84
85 self.departureICAO = readline(f)
86 self.arrivalICAO = readline(f)
87
88 self._readAircraftType(f)
89 self.tailNumber = readline(f)
90 self.numPassengers = int(readline(f))
91 self.numCrew = int(readline(f))
92 self.bagWeight = int(readline(f))
93 self.cargoWeight = int(readline(f))
94 self.mailWeight = int(readline(f))
95 self.route = readline(f)
96
97 departureTime = readline(f)
98 self.departureTime = BookedFlight.getDateTime(date, departureTime)
99
100 arrivalTime = readline(f)
101 self.arrivalTime = BookedFlight.getDateTime(date, arrivalTime)
102
103 if not readline(f)==".NEXT.":
104 raise Exception("Invalid line in flight data")
105
106 def readFromFile(self, f):
107 """Read the data of the flight from a file via the given file
108 object."""
109 date = None
110 departureTime = None
111 arrivalTime = None
112
113 line = f.readline()
114 lineNumber = 0
115 while line:
116 lineNumber += 1
117 line = line.strip()
118
119 hashIndex = line.find("#")
120 if hashIndex>=0: line = line[:hashIndex]
121 if line:
122 equalIndex = line.find("=")
123 lineOK = equalIndex>0
124
125 if lineOK:
126 key = line[:equalIndex].strip()
127 value = line[equalIndex+1:].strip().replace("\:", ":")
128
129 lineOK = key and value
130
131 if lineOK:
132 if key=="callsign": self.callsign = value
133 elif key=="date": date = value
134 elif key=="dep_airport": self.departureICAO = value
135 elif key=="dest_airport": self.arrivalICAO = value
136 elif key=="planecode": self.aircraftType = \
137 self._decodeAircraftType(value)
138 elif key=="tail_nr": self.tailNumber = value
139 elif key=="passenger": self.numPassengers = int(value)
140 elif key=="crew": self.numCrew = int(value)
141 elif key=="bag": self.bagWeight = int(value)
142 elif key=="cargo": self.cargoWeight = int(value)
143 elif key=="mail": self.mailWeight = int(value)
144 elif key=="flight_route": self.route = value
145 elif key=="departure_time": departureTime = value
146 elif key=="arrival_time": arrivalTime = value
147 elif key=="foglalas_id": pass
148 elif key=="planetype": pass
149 else: lineOK = False
150
151 if not lineOK:
152 print "web.BookedFlight.readFromFile: line %d is invalid" % \
153 (lineNumber,)
154
155 line = f.readline()
156
157 if date is not None:
158 if departureTime is not None:
159 self.departureTime = BookedFlight.getDateTime(date,
160 departureTime)
161 if arrivalTime is not None:
162 self.arrivalTime = BookedFlight.getDateTime(date,
163 arrivalTime)
164
165 d = dir(self)
166 for attribute in ["callsign", "departureICAO", "arrivalICAO",
167 "aircraftType", "tailNumber",
168 "numPassengers", "numCrew",
169 "bagWeight", "cargoWeight", "mailWeight",
170 "route", "departureTime", "arrivalTime"]:
171 if attribute not in d:
172 raise Exception("Attribute %s could not be read" % (attribute,))
173
174 def _readAircraftType(self, f):
175 """Read the aircraft type from the given file."""
176 line = readline(f)
177 typeCode = line[:3]
178 self.aircraftType = self._decodeAircraftType(typeCode)
179
180 def _decodeAircraftType(self, typeCode):
181 """Decode the aircraft type from the given typeCode."""
182 if typeCode in self.TYPECODE2TYPE:
183 return self.TYPECODE2TYPE[typeCode]
184 else:
185 raise Exception("Invalid aircraft type code: '" + typeCode + "'")
186
187 def __repr__(self):
188 """Get a representation of the flight."""
189 s = "<Flight: %s-%s, %s, %s-%s," % (self.departureICAO,
190 self.arrivalICAO,
191 self.route,
192 self.departureTime, self.arrivalTime)
193 s += " %d %s," % (self.aircraftType, self.tailNumber)
194 s += " pax=%d, crew=%d, bag=%d, cargo=%d, mail=%d" % \
195 (self.numPassengers, self.numCrew,
196 self.bagWeight, self.cargoWeight, self.mailWeight)
197 s += ">"
198 return s
199
200#------------------------------------------------------------------------------
201
202class Plane(object):
203 """Information about an airplane in the fleet."""
204 def __init__(self, s):
205 """Build a plane info based on the given string.
206
207 The string consists of three, space-separated fields.
208 The first field is the tail number, the second field is the gate
209 number, the third field is the plane's status as a character."""
210 try:
211 words = s.split(" ")
212 tailNumber = words[0]
213 self.tailNumber = tailNumber
214
215 status = words[2] if len(words)>2 else None
216 self.status = const.PLANE_HOME if status=="H" else \
217 const.PLANE_AWAY if status=="A" else \
218 const.PLANE_PARKING if status=="P" else \
219 const.PLANE_UNKNOWN
220
221 gateNumber = words[1] if len(words)>1 else ""
222 self.gateNumber = gateNumber if gateNumber else None
223
224 except:
225 print >> sys.stderr, "Plane string is invalid: '" + s + "'"
226 self.tailNumber = None
227
228 def __repr__(self):
229 """Get the representation of the plane object."""
230 s = "<Plane: %s %s" % (self.tailNumber,
231 "home" if self.status==const.PLANE_HOME else \
232 "away" if self.status==const.PLANE_AWAY else \
233 "parking" if self.status==const.PLANE_PARKING \
234 else "unknown")
235 if self.gateNumber is not None:
236 s += " (gate " + self.gateNumber + ")"
237 s += ">"
238 return s
239
240
241#------------------------------------------------------------------------------
242
243class Fleet(object):
244 """Information about the whole fleet."""
245 def __init__(self, f):
246 """Construct the fleet information by reading the given file object."""
247 self._planes = {}
248 while True:
249 line = readline(f)
250 if not line or line == "#END": break
251
252 plane = Plane(line)
253 if plane.tailNumber is not None:
254 self._planes[plane.tailNumber] = plane
255
256 def isGateConflicting(self, plane):
257 """Check if the gate of the given plane conflicts with another plane's
258 position."""
259 for p in self._planes.itervalues():
260 if p.tailNumber!=plane.tailNumber and \
261 p.status==const.PLANE_HOME and \
262 p.gateNumber==plane.gateNumber:
263 return True
264
265 return False
266
267 def getOccupiedGateNumbers(self):
268 """Get a set containing the numbers of the gates occupied by planes."""
269 gateNumbers = set()
270 for p in self._planes.itervalues():
271 if p.status==const.PLANE_HOME and p.gateNumber:
272 gateNumbers.add(p.gateNumber)
273 return gateNumbers
274
275 def updatePlane(self, tailNumber, status, gateNumber = None):
276 """Update the status of the given plane."""
277 if tailNumber in self._planes:
278 plane = self._planes[tailNumber]
279 plane.status = status
280 plane.gateNumber = gateNumber
281
282 def __iter__(self):
283 """Get an iterator over the planes."""
284 for plane in self._planes.itervalues():
285 yield plane
286
287 def __getitem__(self, tailNumber):
288 """Get the plane with the given tail number.
289
290 If the plane is not in the fleet, None is returned."""
291 return self._planes[tailNumber] if tailNumber in self._planes else None
292
293 def __repr__(self):
294 """Get the representation of the fleet object."""
295 return self._planes.__repr__()
296
297#------------------------------------------------------------------------------
298
299class NOTAM(object):
300 """A NOTAM for an airport."""
301 def __init__(self, begin, notice, end = None, permanent = False,
302 repeatCycle = None):
303 """Construct the NOTAM."""
304 self.begin = begin
305 self.notice = notice
306 self.end = end
307 self.permanent = permanent
308 self.repeatCycle = None
309
310 def __repr__(self):
311 """Get the representation of the NOTAM."""
312 s = "<NOTAM " + str(self.begin)
313 if self.end:
314 s += " - " + str(self.end)
315 elif self.permanent:
316 s += " - PERMANENT"
317 if self.repeatCycle:
318 s += " (" + self.repeatCycle + ")"
319 s += ": " + self.notice
320 s += ">"
321 return s
322
323#------------------------------------------------------------------------------
324
325class NOTAMHandler(xml.sax.handler.ContentHandler):
326 """A handler for the NOTAM database."""
327 def __init__(self, airportICAOs):
328 """Construct the handler for the airports with the given ICAO code."""
329 self._notams = {}
330 for icao in airportICAOs:
331 self._notams[icao] = []
332
333 def startElement(self, name, attrs):
334 """Start an element."""
335 if name!="notam" or \
336 "A" not in attrs or not attrs["A"] or \
337 "B" not in attrs or not attrs["B"] or \
338 "E" not in attrs or not attrs["E"]:
339 return
340
341 icao = attrs["A"]
342 if icao not in self._notams:
343 return
344
345 begin = datetime.datetime.strptime(attrs["B"], "%Y-%m-%d %H:%M:%S")
346
347 c = attrs["C"] if "C" in attrs else None
348 end = datetime.datetime.strptime(c, "%Y-%m-%d %H:%M:%S") if c else None
349
350 permanent = attrs["C_flag"]=="PERM" if "C_flag" in attrs else False
351
352 repeatCycle = attrs["D"] if "D" in attrs else None
353
354 self._notams[icao].append(NOTAM(begin, attrs["E"], end = end,
355 permanent = permanent,
356 repeatCycle = repeatCycle))
357
358 def get(self, icao):
359 """Get the NOTAMs for the given ICAO code."""
360 return self._notams[icao] if icao in self._notams else []
361
362#------------------------------------------------------------------------------
363
364class Result(object):
365 """A result object.
366
367 An instance of this filled with the appropriate data is passed to the
368 callback function on each request."""
369
370 def __repr__(self):
371 """Get a representation of the result."""
372 s = "<Result:"
373 for (key, value) in self.__dict__.iteritems():
374 s += " " + key + "=" + unicode(value)
375 s += ">"
376 return s
377
378#------------------------------------------------------------------------------
379
380class Request(object):
381 """Base class for requests.
382
383 It handles any exceptions and the calling of the callback.
384
385 If an exception occurs during processing, the callback is called with
386 the two parameters: a boolean value of False, and the exception object.
387
388 If no exception occurs, the callback is called with True and the return
389 value of the run() function.
390
391 If the callback function throws an exception, that is caught and logged
392 to the debug log."""
393 def __init__(self, callback):
394 """Construct the request."""
395 self._callback = callback
396
397 def perform(self):
398 """Perform the request.
399
400 The object's run() function is called. If it throws an exception,
401 the callback is called with False, and the exception. Otherwise the
402 callback is called with True and the return value of the run()
403 function. Any exceptions thrown by the callback are caught and
404 reported."""
405 try:
406 result = self.run()
407 returned = True
408 except Exception, e:
409 traceback.print_exc()
410 result = e
411 returned = False
412
413 try:
414 self._callback(returned, result)
415 except Exception, e:
416 print >> sys.stderr, "web.Handler.Request.perform: callback throwed an exception: " + str(e)
417 traceback.print_exc()
418
419#------------------------------------------------------------------------------
420
421class Login(Request):
422 """A login request."""
423 iso88592decoder = codecs.getdecoder("iso-8859-2")
424
425 def __init__(self, callback, pilotID, password, entranceExam):
426 """Construct the login request with the given pilot ID and
427 password."""
428 super(Login, self).__init__(callback)
429
430 self._pilotID = pilotID
431 self._password = password
432 self._entranceExam = entranceExam
433
434 def run(self):
435 """Perform the login request."""
436 md5 = hashlib.md5()
437 md5.update(self._pilotID)
438 pilotID = md5.hexdigest()
439
440 md5 = hashlib.md5()
441 md5.update(self._password)
442 password = md5.hexdigest()
443
444 if self._entranceExam:
445 url = "http://www.virtualairlines.hu/ellenorzo/getflightplan.php?pid=%s" % \
446 (pilotID,)
447 else:
448 url = "http://www.virtualairlines.hu/leker2.php?pid=%s&psw=%s" % \
449 (pilotID, password)
450
451 result = Result()
452 result.entranceExam = self._entranceExam
453
454 f = urllib2.urlopen(url, timeout = 10.0)
455
456 status = readline(f)
457 if self._entranceExam:
458 result.loggedIn = status != "#NOEXAM"
459 else:
460 result.loggedIn = status == ".OK."
461
462 if result.loggedIn:
463 result.pilotID = self._pilotID
464 result.flights = []
465 # FIXME: this may not be the correct behaviour
466 # for an entrance exam, but the website returns
467 # an error
468 if self._entranceExam:
469 result.pilotName = result.pilotID
470 result.exams = ""
471 else:
472 result.pilotName = self.iso88592decoder(readline(f))[0]
473 result.exams = readline(f)
474
475 while True:
476 line = readline(f)
477 if not line or line == "#ENDPIREP": break
478
479 flight = BookedFlight(line)
480 flight.readFromWeb(f)
481 result.flights.append(flight)
482
483 result.flights.sort(cmp = lambda flight1, flight2:
484 cmp(flight1.departureTime,
485 flight2.departureTime))
486
487 f.close()
488
489 return result
490
491#------------------------------------------------------------------------------
492
493class GetFleet(Request):
494 """Request to get the fleet from the website."""
495
496 def __init__(self, callback):
497 """Construct the fleet request."""
498 super(GetFleet, self).__init__(callback)
499
500 def run(self):
501 """Perform the login request."""
502 url = "http://www.virtualairlines.hu/onlinegates_get.php"
503
504 f = urllib2.urlopen(url, timeout = 10.0)
505 result = Result()
506 result.fleet = Fleet(f)
507 f.close()
508
509 return result
510
511#------------------------------------------------------------------------------
512
513class UpdatePlane(Request):
514 """Update the status of one of the planes in the fleet."""
515 def __init__(self, callback, tailNumber, status, gateNumber = None):
516 """Construct the request."""
517 super(UpdatePlane, self).__init__(callback)
518 self._tailNumber = tailNumber
519 self._status = status
520 self._gateNumber = gateNumber
521
522 def run(self):
523 """Perform the plane update."""
524 url = "http://www.virtualairlines.hu/onlinegates_set.php"
525
526 status = "H" if self._status==const.PLANE_HOME else \
527 "A" if self._status==const.PLANE_AWAY else \
528 "P" if self._status==const.PLANE_PARKING else ""
529
530 gateNumber = self._gateNumber if self._gateNumber else ""
531
532 data = urllib.urlencode([("lajstrom", self._tailNumber),
533 ("status", status),
534 ("kapu", gateNumber)])
535
536 f = urllib2.urlopen(url, data, timeout = 10.0)
537 line = readline(f)
538
539 result = Result()
540 result.success = line == "OK"
541
542 return result
543
544#------------------------------------------------------------------------------
545
546class GetNOTAMs(Request):
547 """Get the NOTAMs from EURoutePro and select the ones we are interested
548 in."""
549 def __init__(self, callback, departureICAO, arrivalICAO):
550 """Construct the request for the given airports."""
551 super(GetNOTAMs, self).__init__(callback)
552 self._departureICAO = departureICAO
553 self._arrivalICAO = arrivalICAO
554
555 def run(self):
556 """Perform the retrieval of the NOTAMs."""
557 xmlParser = xml.sax.make_parser()
558 notamHandler = NOTAMHandler([self._departureICAO, self._arrivalICAO])
559 xmlParser.setContentHandler(notamHandler)
560
561 url = "http://notams.euroutepro.com/notams.xml"
562
563 f = urllib2.urlopen(url, timeout = 10.0)
564 try:
565 xmlParser.parse(f)
566 finally:
567 f.close()
568
569 result = Result()
570 result.departureNOTAMs = notamHandler.get(self._departureICAO)
571 result.arrivalNOTAMs = notamHandler.get(self._arrivalICAO)
572
573 return result
574
575#------------------------------------------------------------------------------
576
577class GetMETARs(Request):
578 """Get the METARs from the NOAA website for certain airport ICAOs."""
579
580 def __init__(self, callback, airports):
581 """Construct the request for the given airports."""
582 super(GetMETARs, self).__init__(callback)
583 self._airports = airports
584
585 def run(self):
586 """Perform the retrieval opf the METARs."""
587 url = "http://www.aviationweather.gov/adds/dataserver_current/httpparam?"
588 data = urllib.urlencode([ ("dataSource" , "metars"),
589 ("requestType", "retrieve"),
590 ("format", "csv"),
591 ("stationString", " ".join(self._airports)),
592 ("hoursBeforeNow", "24"),
593 ("mostRecentForEachStation", "constraint")])
594 url += data
595 f = urllib2.urlopen(url, timeout = 10.0)
596 try:
597 result = Result()
598 result.metars = {}
599 for line in iter(f.readline, ""):
600 if len(line)>5 and line[4]==' ':
601 icao = line[0:4]
602 if icao in self._airports:
603 result.metars[icao] = line.strip().split(",")[0]
604 finally:
605 f.close()
606
607 return result
608
609#------------------------------------------------------------------------------
610
611class SendPIREP(Request):
612 """A request to send a PIREP to the MAVA website."""
613 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
614 const.FLIGHTTYPE_OLDTIMER : "OT",
615 const.FLIGHTTYPE_VIP : "VIP",
616 const.FLIGHTTYPE_CHARTER : "CHARTER" }
617
618 _latin2Encoder = codecs.getencoder("iso-8859-2")
619
620 def __init__(self, callback, pirep):
621 """Construct the request for the given PIREP."""
622 super(SendPIREP, self).__init__(callback)
623 self._pirep = pirep
624
625 def run(self):
626 """Perform the retrieval opf the METARs."""
627 url = "http://www.virtualairlines.hu/malevacars.php"
628
629 pirep = self._pirep
630
631 data = {}
632 data["acarsdata"] = pirep.getACARSText()
633
634 bookedFlight = pirep.bookedFlight
635 data["foglalas_id"] = bookedFlight.id
636 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
637 data["fltnum"] = bookedFlight.callsign
638 data["depap"] = bookedFlight.departureICAO
639 data["arrap"] = bookedFlight.arrivalICAO
640 data["pass"] = str(bookedFlight.numPassengers)
641 data["crew"] = str(bookedFlight.numCrew)
642 data["cargo"] = str(pirep.cargoWeight)
643 data["bag"] = str(bookedFlight.bagWeight)
644 data["mail"] = str(bookedFlight.mailWeight)
645
646 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
647 data["onoff"] = "1" if pirep.online else "0"
648 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
649 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
650 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
651 pirep.blockTimeStart)
652 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
653 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
654 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
655 pirep.flightTimeStart)
656 data["timecomm"] = pirep.getTimeComment()
657 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
658 data["dep_rwy"] = pirep.departureRunway
659 data["arr_rwy"] = pirep.arrivalRunway
660 data["wea_dep"] = pirep.departureMETAR
661 data["wea_arr"] = pirep.arrivalMETAR
662 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
663 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
664 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
665 else:
666 data["mod_alt"] = ""
667 data["sid"] = pirep.sid
668 data["navroute"] = pirep.route
669 data["star"] = pirep.getSTAR()
670 data["aprtype"] = pirep.approachType
671 data["diff"] = "2"
672 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
673 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
674 data["kritika"] = pirep.getRatingText()
675 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
676 data["distance"] = "%.3f" % (pirep.flownDistance,)
677 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
678
679 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
680 try:
681 result = Result()
682 line = f.readline().strip()
683 print "PIREP result from website:", line
684 result.success = line=="OK"
685 result.alreadyFlown = line=="MARVOLT"
686 result.notAvailable = line=="NOMORE"
687 finally:
688 f.close()
689
690 return result
691
692#------------------------------------------------------------------------------
693
694class SendPIREP(Request):
695 """A request to send a PIREP to the MAVA website."""
696 _flightTypes = { const.FLIGHTTYPE_SCHEDULED : "SCHEDULED",
697 const.FLIGHTTYPE_OLDTIMER : "OT",
698 const.FLIGHTTYPE_VIP : "VIP",
699 const.FLIGHTTYPE_CHARTER : "CHARTER" }
700
701 _latin2Encoder = codecs.getencoder("iso-8859-2")
702
703 def __init__(self, callback, pirep):
704 """Construct the request for the given PIREP."""
705 super(SendPIREP, self).__init__(callback)
706 self._pirep = pirep
707
708 def run(self):
709 """Perform the sending of the PIREP."""
710 url = "http://www.virtualairlines.hu/malevacars.php"
711
712 pirep = self._pirep
713
714 data = {}
715 data["acarsdata"] = pirep.getACARSText()
716
717 bookedFlight = pirep.bookedFlight
718 data["foglalas_id"] = bookedFlight.id
719 data["repdate"] = bookedFlight.departureTime.date().strftime("%Y-%m-%d")
720 data["fltnum"] = bookedFlight.callsign
721 data["depap"] = bookedFlight.departureICAO
722 data["arrap"] = bookedFlight.arrivalICAO
723 data["pass"] = str(bookedFlight.numPassengers)
724 data["crew"] = str(bookedFlight.numCrew)
725 data["cargo"] = str(pirep.cargoWeight)
726 data["bag"] = str(bookedFlight.bagWeight)
727 data["mail"] = str(bookedFlight.mailWeight)
728
729 data["flttype"] = SendPIREP._flightTypes[pirep.flightType]
730 data["onoff"] = "1" if pirep.online else "0"
731 data["bt_dep"] = util.getTimestampString(pirep.blockTimeStart)
732 data["bt_arr"] = util.getTimestampString(pirep.blockTimeEnd)
733 data["bt_dur"] = util.getTimeIntervalString(pirep.blockTimeEnd -
734 pirep.blockTimeStart)
735 data["ft_dep"] = util.getTimestampString(pirep.flightTimeStart)
736 data["ft_arr"] = util.getTimestampString(pirep.flightTimeEnd)
737 data["ft_dur"] = util.getTimeIntervalString(pirep.flightTimeEnd -
738 pirep.flightTimeStart)
739 data["timecomm"] = pirep.getTimeComment()
740 data["fuel"] = "%.0f" % (pirep.fuelUsed,)
741 data["dep_rwy"] = pirep.departureRunway
742 data["arr_rwy"] = pirep.arrivalRunway
743 data["wea_dep"] = pirep.departureMETAR
744 data["wea_arr"] = pirep.arrivalMETAR
745 data["alt"] = "FL%.0f" % (pirep.filedCruiseAltitude/100.0,)
746 if pirep.filedCruiseAltitude!=pirep.cruiseAltitude:
747 data["mod_alt"] = "FL%.0f" % (pirep.cruiseAltitude/100.0,)
748 else:
749 data["mod_alt"] = ""
750 data["sid"] = pirep.sid
751 data["navroute"] = pirep.route
752 data["star"] = pirep.getSTAR()
753 data["aprtype"] = pirep.approachType
754 data["diff"] = "2"
755 data["comment"] = SendPIREP._latin2Encoder(pirep.comments)[0]
756 data["flightdefect"] = SendPIREP._latin2Encoder(pirep.flightDefects)[0]
757 data["kritika"] = pirep.getRatingText()
758 data["flightrating"] = "%.1f" % (max(0.0, pirep.rating),)
759 data["distance"] = "%.3f" % (pirep.flownDistance,)
760 data["insdate"] = datetime.date.today().strftime("%Y-%m-%d")
761
762 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
763 try:
764 result = Result()
765 line = f.readline().strip()
766 print "PIREP result from website:", line
767 result.success = line=="OK"
768 result.alreadyFlown = line=="MARVOLT"
769 result.notAvailable = line=="NOMORE"
770 finally:
771 f.close()
772
773 return result
774
775#------------------------------------------------------------------------------
776
777class SendACARS(Request):
778 """A request to send an ACARS to the MAVA website."""
779 _latin2Encoder = codecs.getencoder("iso-8859-2")
780
781 def __init__(self, callback, acars):
782 """Construct the request for the given PIREP."""
783 super(SendACARS, self).__init__(callback)
784 self._acars = acars
785
786 def run(self):
787 """Perform the sending of the ACARS."""
788 url = "http://www.virtualairlines.hu/acars2/acarsonline.php"
789
790 acars = self._acars
791 bookedFlight = acars.bookedFlight
792
793 data = {}
794 data["pid"] = acars.pid
795 data["pilot"] = SendACARS._latin2Encoder(acars.pilotName)[0]
796
797 data["pass"] = str(bookedFlight.numPassengers)
798 data["callsign"] = bookedFlight.callsign
799 data["airplane"] = BookedFlight.TYPE2TYPECODE[bookedFlight.aircraftType]
800 data["from"] = bookedFlight.departureICAO
801 data["to"] = bookedFlight.arrivalICAO
802 data["lajstrom"] = bookedFlight.tailNumber
803
804 data["block_time"] = acars.getBlockTimeText()
805 data["longitude"] = str(acars.state.longitude)
806 data["latitude"] = str(acars.state.latitude)
807 data["altitude"] = str(acars.state.altitude)
808 data["speed"] = str(acars.state.groundSpeed)
809
810 data["event"] = acars.getEventText()
811
812 f = urllib2.urlopen(url, urllib.urlencode(data), timeout = 10.0)
813 try:
814 result = Result()
815 finally:
816 f.close()
817
818 return result
819
820#------------------------------------------------------------------------------
821
822class Handler(threading.Thread):
823 """The handler for the web services.
824
825 It can process one request at a time. The results are passed to a callback
826 function."""
827 def __init__(self):
828 """Construct the handler."""
829 super(Handler, self).__init__()
830
831 self._requests = []
832 self._requestCondition = threading.Condition()
833
834 self.daemon = True
835
836 def login(self, callback, pilotID, password, entranceExam = False):
837 """Enqueue a login request."""
838 self._addRequest(Login(callback, pilotID, password, entranceExam))
839
840 def getFleet(self, callback):
841 """Enqueue a fleet retrieval request."""
842 self._addRequest(GetFleet(callback))
843
844 def updatePlane(self, callback, tailNumber, status, gateNumber = None):
845 """Update the status of the given plane."""
846 self._addRequest(UpdatePlane(callback, tailNumber, status, gateNumber))
847
848 def getNOTAMs(self, callback, departureICAO, arrivalICAO):
849 """Get the NOTAMs for the given two airports."""
850 self._addRequest(GetNOTAMs(callback, departureICAO, arrivalICAO))
851
852 def getMETARs(self, callback, airports):
853 """Get the METARs for the given airports."""
854 self._addRequest(GetMETARs(callback, airports))
855
856 def sendPIREP(self, callback, pirep):
857 """Send the given PIREP."""
858 self._addRequest(SendPIREP(callback, pirep))
859
860 def sendACARS(self, callback, acars):
861 """Send the given ACARS"""
862 self._addRequest(SendACARS(callback, acars))
863
864 def run(self):
865 """Process the requests."""
866 while True:
867 with self._requestCondition:
868 while not self._requests:
869 self._requestCondition.wait()
870 request = self._requests[0]
871 del self._requests[0]
872
873 request.perform()
874
875 def _addRequest(self, request):
876 """Add the given request to the queue."""
877 with self._requestCondition:
878 self._requests.append(request)
879 self._requestCondition.notify()
880
881#------------------------------------------------------------------------------
882
883if __name__ == "__main__":
884 import time
885
886 def callback(returned, result):
887 print returned, unicode(result)
888
889 handler = Handler()
890 handler.start()
891
892 #handler.login(callback, "P096", "V5fwj")
893 #handler.getFleet(callback)
894 # Plane: HA-LEG home (gate 67)
895 #handler.updatePlane(callback, "HA-LQC", const.PLANE_AWAY, "72")
896 #time.sleep(3)
897 #handler.getFleet(callback)
898 #time.sleep(3)
899
900 #handler.getNOTAMs(callback, "LHBP", "EPWA")
901 handler.getMETARs(callback, ["LHBP", "EPWA"])
902 time.sleep(5)
903
904
905#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.