source: src/mlx/web.py@ 208:22ff615383e9

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

It is now possible to cancel a flight and to start a new one at the end and also to refresh the list of flights.

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