source: src/mlx/web.py@ 189:2d89178707a0

Last change on this file since 189:2d89178707a0 was 188:c737b2c79a8b, checked in by István Váradi <ivaradi@…>, 13 years ago

If the date is 0000-00-00 it is changed to 0001-01-01

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